Error processing request

Parameters

CONTENT_LENGTH0
REQUEST_METHODGET
REQUEST_URI/revision/How+to+totally+handle+listbox+selection?V=2
QUERY_STRINGV=2
CONTENT_TYPE
DOCUMENT_URI/revision/How+to+totally+handle+listbox+selection
DOCUMENT_ROOT/var/www/nikit/nikit/nginx/../docroot
SCGI1
SERVER_PROTOCOLHTTP/1.1
HTTPSon
REMOTE_ADDR108.162.216.6
REMOTE_PORT17854
SERVER_PORT4443
SERVER_NAMEwiki.tcl-lang.org
HTTP_HOSTwiki.tcl-lang.org
HTTP_CONNECTIONKeep-Alive
HTTP_ACCEPT_ENCODINGgzip, br
HTTP_X_FORWARDED_FOR3.138.141.202
HTTP_CF_RAY87b80cb96da6e1f3-ORD
HTTP_X_FORWARDED_PROTOhttps
HTTP_CF_VISITOR{"scheme":"https"}
HTTP_ACCEPT*/*
HTTP_USER_AGENTMozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; [email protected])
HTTP_CF_CONNECTING_IP3.138.141.202
HTTP_CDN_LOOPcloudflare
HTTP_CF_IPCOUNTRYUS

Body


Error

Unknow state transition: LINE -> END

-code

1

-level

0

-errorstack

INNER {returnImm {Unknow state transition: LINE -> END} {}} CALL {my render_wikit {How to totally handle listbox selection} \[ABU\]\ 5-apr-2005\ (*\ in\ progress\ ...)\n\nThe\ problem:\n\nI\ have\ a\ listbox\ and\ a\ button.\ The\ button\ should\ be\ enabled\ when\ a\ selected\ element\ exists,\ and\ it\ should\ be\ disabled\ when\ no\ element\ is\ selected.\n\n----\n\nBefore\ explaining\ the\ solution\ found,\ I\ think\ it\ is\ important\ to\ show\ the\nmethod\ used\ for\ testing.\nI\ will\ show\ you\ a\ simple\ user\ interface\ made\ with\ \n\ \ \ *\ an\ (enahanced)\ listbox,\n\ \ \ *\ a\ related\ button\ (that\ will\ be\ enabled\ only\ when\ there's\ a\ selection\ in\ the\ listbox)\n\ \ \ *\ an\ entry-widget\n\nThis\ latter\ entry-widget\ is\ important\ because\ its\ role\ is\ to\ 'claim'\ the\nselection,\ so\ that\ we\ can\ verify\ if\ the\ (enhanced)\ listbox\ properly\nreacts\ when\ it\ loses\ the\ selection.\n\n'''NOTE:'''\ instead\ of\ an\ entry-widget\ we\ could\ use\ other\ widgets\ able\ to\ claim\ the\ selection.\nAmong\ standard\ widgets\ these\ are:\n\ \ \ *\ entry\n\ \ \ *\ listbox\n\ \ \ *\ text\nAn\ entry-widget\ has\ been\ choosen\ just\ because\ it\ is\ the\ simpler\ widget.\nAnyway,\ the\ solution\ (the\ enhanced\ listbox)\ is\ independent\ of,\ or\nbetter,\ is\ unaware\ of,\ the\ 'other'\ widgets\ that\ could\ claim\ the\nselection.\n\n\nIt\ is\ important\ to\ remark\ here\ that\ a\ selection\ in\ a\ listbox\ could\ change\nfor\ two\ kind\ of\ reasons:\n\ \ \ *\ in\ response\ to\ changes\ made\ by\ a\ PROGRAM\n\ \ \ *\ in\ response\ to\ changes\ made\ by\ a\ USER\n\nIt\ is\ a\ common\ and\ well-documented\ tecnique\ to\ intercept\ USER\ changes,\ by\nproviding\ a\ callback\ for\ the\ <<ListboxSelect>>\ event.\ This\ technique\ is\nnot\ totally\ perfect\ (as\ you\ will\ see\ later)\ but,\ more\ important,\ this\ntechnique\ cannot\ be\ used\ for\ intercepting\ changes\ made\ by\ a\ PROGRAM.\n\nWhat\ I\ want\ to\ say\ is\ that,\ when\ a\ PROGRAM\ changes\ the\ selection\ in\ a\ listbox,\ e.g.\n\ #\ select\ the\ first\ row\ in\ a\ listbox\ \$lb\n\ \$lb\ select\ set\ 0\ \ \n\ #\ delete\ the\ first\ row\n\ \$lb\ delete\ 0\n'''NO'''\ <<ListboxSelect>>\ event\ is\ generated.\nI\nn\ these\ cases\ it\ is\ the\ programmer's\ responsability\ add\ some\ code\nenabling/disabling\ the\ 'related\ button'.\n\n''a\ simple\ solution\ I\ recommend\ for\ these\ cases\ is\ the\ following:\n\ \ if\ you\ have\ some\ code\ that\ *may*\ change\ the\ selection\ in\ a\ listbox,\n\ \ simply\ generate\ a\ virtual\ event\ after.''\nE.g\n\ \ \ \ ...\n\ \ \ \ \$lb\ selection\ clear\ 0\ end\n\ \ \ \ ...\n\ \ \ should\ be\ written\ as\n\ \ \ \ ...\n\ \ \ \ \$lb\ selection\ clear\ 0\ end\n\ \ \ \ event\ generate\ \$lb\ <<ListboxSelect>>\n\ \ \ \ ...\n\nThe\ other\ case,\ when\ the\ selection\ changes\ in\ response\ to\ changes\ made\ by\na\ USER,\ is\ more\ complex\ ...\n\nOf\ course\ the\ application\ cannot\ wait\ for\ user\ changes\;\ some\ tecniques\nfor\ controlling\ the\ event-loop\ are\ required\ ...\n\nI\ will\ show\ you\ how\ to\ provide\ an\ handler\ to\ deal\ with\ ALL\ changes\ made\ by\nthe\ USER.\n\n------\n\nAfter\ these\ long\ premise,\ we\ are\ ready\ for\ the\ solution.\n\nThe\ solution\ is\ based\ on\ the\ following\ principles:\n\n'''(A)\ intercept\ all\ the\ <<ListboxSelect>>\ generated\ events.'''\n\n\nThis\ way\ allows\ you\ to\ know\ when\ a\ user\ selects\ an\ element\ of\ the\ listbox\ and\n(if\ \"-selectmode\"\ option\ is\ \"multiple\"\ or\ \"extended\")\ when\ a\ user\ndeselects\ the\ last\ element.\n\nbind\ \$lb\ <<ListboxSelect>>\ \[list\ ::cb_selectionChanged\ %W\]\ \n\nproc\ ::cb_selectionChanged\ \{w\ args\}\ \{\n\ \ if\ \{\ \[\$w\ curselection\]\ ==\ \"\"\ \}\ \{\n\ \ \ \ \ #\ listbox\ has\ no\ selected\ items\n\ \ \}\ else\ \{\n\ \ \ \ \ #\ listbox\ has\ one\ or\ more\ selected\ items\n\ \ \}\n\nUnfortunately\ there\ is\ lack\;\ if\ user\ makes\ a\ selection\ in\ another\ widget\n(e.g\ an\ entry-widget),\ all\ the\ selected\ elements\ of\ the\ listbox\ndisappear,\ and\ worst,\ NO\ event\ is\ generated.\n\nNOTE:\ when\ user\ clicks-in\ an\ entry-widget,\ or\ he\ enters\ some\ text,\nnothing\ happens\ to\ the\ listbox\;\ it\ is\ only\ when\ the\ user\ *selects*\ some\ntext\ in\ an\ entry-widget\ that\ the\ listbox\ loses\ all\ its\ selected\ items\n(provided\ that\ listbox\ option\ \"-exportselection\"\ is\ \"1\"\ (default))\n\n(B)\ register\ a\ callback\ so\ that\ listbox\ will\ be\ notified\ when\ another\nwidget\ claims\ the\ selection.\n\n(indenta)\nNote\ that\ there\ can\ be\ only\ one\ widget\ registered\ for\ this\ notification,\nand\ this\ widget\ should\ be\ the\ widget\ currently\ owning\ the\ selection.\nTherefore,\ each\ time\ a\ listbox\ widget\ (you\ could\ have\ more\ than\ one)\ gets\nthe\ selection,\ it\ should\ register\ itself\ for\ this\ kind\ of\ notification.\nFortunately,\ this\ is\ easy,\ because\ each\ time\ the\ <<ListboxSelect>>\ event\nis\ generated,\ (see\ above),\ it\ means\ that\ THAT\ listbox\ has\ got\ the\nselection.\nAll\ we\ need\ to\ add\ is\ the\ following\n\n\ ##\ ----------------------------------------------------------------\n\ ##\ generic\ code\ for\ enhanced\ listbox\n\ ##\ ----------------------------------------------------------------\n\ \n\ \n\ \ #\ define\ an\ event-handler\ valid\ for\ the\ whole\ 'Listbox'\ class\nbind\ Listbox\ <<ListboxSelect>>\ \[list\ gotSelectEvent\ %W\]\n\nproc\ gotSelectEvent\ \{w\}\ \{\n\ \ \ puts\ \"Listbox-class\ received\ <<ListboxSelect>>\"\n\ \ \ if\ \{\ \[\$w\ curselection\]\ !=\ \"\"\ \ &&\ \ \[\$w\ cget\ -exportselection\]\ ==\ 1\ \}\ \{\n\ \ \ \ \ \ \ \ \ selection\ own\ -command\ \[list\ lostSelection\ \$w\]\ \$w\n\ \ \ \}\ \n\}\n\nproc\ lostSelection\ \{w\}\ \{\n\ \ \ if\ \{\ \[\$w\ cget\ -exportselection\]\ ==\ 1\ \}\ \{\n\ \ \ \ \ \ puts\ \"Listbox\ \$w\ lost\ selection\"\n\ \ \ \ \ \ \$w\ selection\ clear\ 0\ end\n\ \ \ \ \ \ event\ generate\ \$w\ <<ListboxSelect>>\n\ \ \ \}\n\}\n\nNote\ that\ I\ wrote\ anything\ tied\ to\ a\ 'particular'\ listbox\ instance,\ nor\ a\n'particular'\ event-handler\ for\ a\ <<ListboxSelect>>\ tied\ to\ a\ listbox.\nThere's\ only\ an\ event-handler\ valid\ for\ ALL\ listboxes.\ Particular\ninstances\ of\ listbox\ can\ (should)\ write\ their\ own\ peculiar\ event-handler.\nSomething\ like\ this:\n\n====\n\ #\ remember\ you\ MUST\ load\ the\ above\ 'generic\ code\ for\ enhanced\ listbox'\n...\n\ \ #\ purpose\ of\ this\ proc\ is\ to\ enable/disable\ the\ button\ \$b\n\ \ #\ \ depending\ on\ the\ selected\ rows\ of\ the\ listbox\ \$lb\nproc\ MY_selectHandler\ \{lb\ b\}\ \{\n\ \ \ if\ \{\ \[\$lb\ curselection\]\ ==\ \"\"\ \}\ \{\n\ \ \ \ \ \ \$b\ configure\ -state\ disabled\n\ \ \ \}\ else\ \{\n\ \ \ \ \ \ \$b\ configure\ -state\ normal\n\ \ \ \}\n\}\n\nlistbox\ .lb\nbutton\ .b\ -state\ disabled\ -text\ \"button\ related\ to\ listbox\"\ \npack\ .lb\ .b\nbind\ .lb\ <<ListboxSelect>>\ \[list\ MY_selectHandler\ .lb\ .b\]\n\n...\n\n\nAnd\ now,\ here\ is\ a\ complete\ example.\ experiment\ it\ !\n\n====\n\n\ ##\ ----------------------------------------------------------------\n\ ##\ generic\ code\ for\ enhanced\ listbox\n\ ##\ ----------------------------------------------------------------\n\ \n\ \n\ \ #\ define\ an\ event-handler\ valid\ for\ the\ whole\ 'Listbox'\ class\nbind\ Listbox\ <<ListboxSelect>>\ \[list\ gotSelectEvent\ %W\]\n\nproc\ gotSelectEvent\ \{w\}\ \{\n\ \ \ puts\ \"Listbox-class\ received\ <<ListboxSelect>>\"\n\ \ \ if\ \{\ \[\$w\ curselection\]\ !=\ \"\"\ \ &&\ \ \[\$w\ cget\ -exportselection\]\ ==\ 1\ \}\ \{\n\ \ \ \ \ \ \ \ \ selection\ own\ -command\ \[list\ lostSelection\ \$w\]\ \$w\n\ \ \ \}\ \n\}\n\nproc\ lostSelection\ \{w\}\ \{\n\ \ \ if\ \{\ \[\$w\ cget\ -exportselection\]\ ==\ 1\ \}\ \{\n\ \ \ \ \ \ puts\ \"Listbox\ \$w\ lost\ selection\"\n\ \ \ \ \ \ \$w\ selection\ clear\ 0\ end\n\ \ \ \ \ \ event\ generate\ \$w\ <<ListboxSelect>>\n\ \ \ \}\n\}\n\n\ ##\ ----------------------------------------------------------------\n\ ##\ sample\ code\ for\ testing\ ....\n\ ##\ ----------------------------------------------------------------\n\n\ \ #\ define\ here\ a\ proc\ for\ creating\ a\ listbox\ with\ a\ related-button\n\ \ #\ \ plus\ some\ checkbuttons/radiobuttons\ for\ changing\ its\ properties\ \ \nproc\ myComplexListbox\ \{w\}\ \{\n\ \ \ frame\ \$w\ -relief\ raised\ -bd\ 2\ -padx\ 5\ -pady\ 5\n\n\ \ \ \ #\ create\ a\ listbox\;\ it\ is\ an\ enhnaced\ listbox\ thanks\ to\ the\n\ \ \ \ #\ \ extended\ Listbox-class\ handler\ defined\ above\n\ \ \ listbox\ \$w.lb\n\ \ \ button\ \$w.b\ -text\ \"apply\ on\ selected\ item\"\ \\\n\ \ \ \ \ \ -command\ \[list\ showSelected\ \$w.lb\]\n\ \ \ \$w.b\ configure\ -state\ disabled\n\ \ \ pack\ \$w.lb\ \$w.b\n\ \ \ \ #\ bind\ event\ to\ a\ custom\ handler\ (enabling/disabling\ related\ button)\n\ \ \ bind\ \$w.lb\ <<ListboxSelect>>\ \[list\ mySelectHandler\ \$w\]\n\n\n\ \ \ \ #\ other\ controls\ ...\n\ \ \ \ \n\ \ \ set\ ::control(\$w,mode)\ browse\n\ \ \ foreach\ mode\ \{single\ browse\ extended\ multiple\}\ \{\n\ \ \ \ \ \ radiobutton\ \$w.rb_\$mode\ -value\ \$mode\ -variable\ ::control(\$w,mode)\ \\\n\ \ \ \ \ \ \ \ -text\ \$mode\ \\\n\ \ \ \ \ \ \ \ -command\ \[list\ \$w.lb\ configure\ -selectmode\ \$mode\]\n\ \ \ \ \ \ pack\ \$w.rb_\$mode\n\ \ \ \}\n\ \ \ \ \ \n\ \ \ set\ ::control(\$w,exportselection)\ 1\n\ \ \ checkbutton\ \$w.expsel\ -text\ \"-exportselection\"\ \\\n\ \ \ \ \ \ -variable\ ::control(\$w,exportselection)\ \\\n\ \ \ \ \ \ -command\ \[list\ setExportSelection\ \$w\]\n\ \ \ pack\ \$w.expsel\n\ \ \ return\ \$w\n\}\n\nproc\ showSelected\ \{lb\}\ \{\n\ \ \ puts\ \"selected\ element\ is\ <\[\$lb\ curselection\]>\"\n\}\n\nproc\ setExportSelection\ \{w\}\ \{\n\ \ \$w.lb\ configure\ -exportselection\ \$::control(\$w,exportselection)\n\}\ \n\n\nproc\ mySelectHandler\ \{w\}\ \{\n\ \ puts\ \"<\$w.lb>\ received\ <<ListboxSelect>>\"\n\ \ \ #\ note\ that\ if\ -selectmode\ is\ multiple/extended,\ and\ the\ last\ item\n\ \ \ #\ \ is\ deselected,\ then\ <<ListboxSelect>>\ is\ generated\ !\n\ \ \ \n\ \ if\ \{\ \[\$w.lb\ curselection\]\ !=\ \"\"\ \}\ \{\n\ \ \ \ \ \$w.b\ configure\ -state\ normal\ \ \ \n\ \ \}\ else\ \{\n\ \ \ \ \ \$w.b\ configure\ -state\ disabled\n\ \ \}\n\}\n\n\npack\ \[myComplexListbox\ .m1\]\n.m1.lb\ insert\ 0\ aa\ bb\ cc\ dd\npack\ \[myComplexListbox\ .m2\]\n.m2.lb\ insert\ 0\ xx\ yy\ zz\n\n\ #\ some\ 'other'\ standard\ widgets\ that\ could\ claim\ the\ selection\ ...\npack\ \[labelframe\ .other\ -text\ \"other\ widgets..\"\ -padx\ 5\ -pady\ 5\]\npack\ \[entry\ .other.e1\]\npack\ \[entry\ .other.e2\]\n\n====\n\nAs\ a\ final\ exercise\ I\ rewrote\ the\ same\ solution\ in\ a\ 00-way\ using\ Snit.\nThis\ latter\ solution\ is\ more\ elegant,\ providing\ a\ new\ widget\ \"extListbox\"\nhiding\ all\ the\ internal\ details,\ without\ the\ need\ to\ occupy\ an\ event\nhandler\ for\ the\ Listbox\ class.\nHere\ is\ the\ 'generic'\ Snit\ code\ providing\ the\ new\ \"extListBox\"\ widget\n====\npackage\ require\ snit\ 0.97\n\n::snit::widgetadaptor\ extListbox\ \{\n\ \ \ \n\ \ \ option\ -exportselection\ 1\n\n\ \ \ delegate\ method\ *\ to\ hull\n\ \ \ delegate\ option\ *\ to\ hull\ except\ \{\ -exportselection\ \}\ \n\n\ \ \ \ #define\ a\ 'pseudo'\ Class\ binding\n\ \ \ typeconstructor\ \{\n\ \ \ \ \ \ bind\ ExtListbox\ <<ListboxSelect>>\ \[myproc\ gotListboxSelect\ %W\]\n\ \ \ \}\n\n\n\ \ \ constructor\ \{args\}\ \{\n\ \ \ \ \ \ installhull\ using\ listbox\n\ \ \ \ \ \ \$self\ configurelist\ \$args\n\ \ \ \ \ \ bindtags\ \$win\ \[linsert\ \[bindtags\ \$win\]\ 1\ ExtListbox\]\n\ \ \ \}\n\ \ \ \n\n\ \ \ \ \ \ #\ intercept\ option\ -exportselection.\n\ \ \ onconfigure\ -exportselection\ \{value\}\ \{\n\ \ \ \ \ \ \$hull\ configure\ -exportselection\ \$value\n\ \ \ \ \ \ set\ options(-exportselection)\ \$value\n\ \ \ \ \ \ if\ \{\ \$value\ &&\ \ \[\$win\ curselection\]\ !=\ \"\"\ \}\ \{\ \n\ \ \ \ \ \ \ \ \ selection\ own\ -command\ \[myproc\ lostSelection\ \$win\]\ \$win\n\ \ \ \ \ \ \}\ \ \ \ \ \ \n\ \ \ \}\n\n\n\ \ \ proc\ gotListboxSelect\ \{w\}\ \{\n\ \ \ \ \ \ if\ \{\ \[\$w\ curselection\]\ !=\ \"\"\ \ &&\ \ \[\$w\ cget\ -exportselection\]\ ==\ 1\ \}\ \{\n\ \ \ \ \ \ \ \ \ selection\ own\ -command\ \[myproc\ lostSelection\ \$w\]\ \$w\n\ \ \ \ \ \ \}\ \n\ \ \ \}\n\n\ \ \ proc\ lostSelection\ \{w\}\ \{\n\ \ \ \ \ \ if\ \{\ \[\$w\ cget\ -exportselection\]\ ==\ 1\ \}\ \{\n\ \ \ \ \ \ \ \ \ \$w\ selection\ clear\ 0\ end\n\ \ \ \ \ \ \ \ \ event\ generate\ \$w\ <<ListboxSelect>>\n\ \ \ \ \ \ \}\n\ \ \ \}\n\}\n====\n\nand\ here\ is\ the\ code\ for\ testing.\n\n======\n\n\ #\ NOTE:\ Snit-widget\ extListbox\ is\ required\n\nproc\ user_gotListboxSelect\ \{w\}\ \{\n\ \ puts\ \"<\$w.lb>\ received\ <<ListboxSelect>>\"\n\ \ \ #\ note\ that\ if\ -selectmode\ is\ multiple/extended,\ and\ the\ last\ item\n\ \ \ #\ \ is\ deselected,\ then\ <<ListboxSelect>>\ is\ generated\ !\n\ \ \ \n\ \ if\ \{\ \[\$w.lb\ curselection\]\ !=\ \"\"\ \}\ \{\n\ \ \ \ \ \$w.b\ configure\ -state\ normal\ \ \ \n\ \ \}\ else\ \{\n\ \ \ \ \ \$w.b\ configure\ -state\ disabled\n\ \ \}\n\n\}\n\nproc\ user_showSelected\ \{lb\}\ \{\n\ \ \ puts\ \"selected\ element\ is\ <\[\$lb\ curselection\]>\"\n\}\n\nproc\ user_setExportSelection\ \{w\}\ \{\n\ \ \$w.lb\ configure\ -exportselection\ \$::control(\$w,exportselection)\n\}\ \n\nproc\ myComplexListbox\ \{w\}\ \{\n\ \ \ frame\ \$w\ -relief\ raised\ -bd\ 2\ -padx\ 5\ -pady\ 5\n\n\ \ \ extListbox\ \$w.lb\n\ \ \ button\ \$w.b\ -text\ \"apply\ on\ selected\ item\"\ \\\n\ \ \ \ \ \ -command\ \[list\ user_showSelected\ \$w.lb\]\n\ \ \ \$w.b\ configure\ -state\ disabled\n\ \ \ pack\ \$w.lb\ \$w.b\n\ \ \ \n\ \ \ bind\ \$w.lb\ <<ListboxSelect>>\ \[list\ user_gotListboxSelect\ \$w\]\n\n\n\ \ \ \ #\ other\ controls\ ...\n\ \ \ \ \n\ \ \ set\ ::control(\$w,mode)\ browse\n\ \ \ foreach\ mode\ \{single\ browse\ extended\ multiple\}\ \{\n\ \ \ \ \ \ radiobutton\ \$w.rb_\$mode\ -value\ \$mode\ -variable\ ::control(\$w,mode)\ -text\ \$mode\ \\\n\ \ \ \ \ \ \ \ -command\ \[list\ \$w.lb\ configure\ -selectmode\ \$mode\]\n\ \ \ \ \ \ pack\ \$w.rb_\$mode\n\ \ \ \}\n\ \ \ \ \ \n\ \ \ set\ ::control(\$w,exportselection)\ 1\n\ \ \ checkbutton\ \$w.expsel\ -text\ \"-exportselection\"\ \\\n\ \ \ \ \ \ -variable\ ::control(\$w,exportselection)\ \\\n\ \ \ \ \ \ -command\ \[list\ user_setExportSelection\ \$w\ \]\n\ \ \ pack\ \$w.expsel\n\ \ \ return\ \$w\n\}\n\n\n\npack\ \[myComplexListbox\ .m1\]\n.m1.lb\ insert\ 0\ aa\ bb\ cc\ dd\npack\ \[myComplexListbox\ .m2\]\n.m2.lb\ insert\ 0\ xx\ yy\ zz\n\npack\ \[labelframe\ .other\ -text\ \"other\ widgets..\"\ -padx\ 5\ -pady\ 5\]\npack\ \[entry\ .other.e1\]\npack\ \[entry\ .other.e2\]\n\n----\n\nWhat's\ next\ ?\n\nWell,\ I\ think\ this\ exercise\ can\ be\ generalized\ for\ other\ standard\nwidgets,\ such\ as\ text-widget\ and\ tablelist.\n\nBut\ the\ better\ things\ will\ be\ this\ idea\ be\ incorporated\ in\ the\ standard\nlistbox\ widget\ ... regexp2} CALL {my render {How to totally handle listbox selection} \[ABU\]\ 5-apr-2005\ (*\ in\ progress\ ...)\n\nThe\ problem:\n\nI\ have\ a\ listbox\ and\ a\ button.\ The\ button\ should\ be\ enabled\ when\ a\ selected\ element\ exists,\ and\ it\ should\ be\ disabled\ when\ no\ element\ is\ selected.\n\n----\n\nBefore\ explaining\ the\ solution\ found,\ I\ think\ it\ is\ important\ to\ show\ the\nmethod\ used\ for\ testing.\nI\ will\ show\ you\ a\ simple\ user\ interface\ made\ with\ \n\ \ \ *\ an\ (enahanced)\ listbox,\n\ \ \ *\ a\ related\ button\ (that\ will\ be\ enabled\ only\ when\ there's\ a\ selection\ in\ the\ listbox)\n\ \ \ *\ an\ entry-widget\n\nThis\ latter\ entry-widget\ is\ important\ because\ its\ role\ is\ to\ 'claim'\ the\nselection,\ so\ that\ we\ can\ verify\ if\ the\ (enhanced)\ listbox\ properly\nreacts\ when\ it\ loses\ the\ selection.\n\n'''NOTE:'''\ instead\ of\ an\ entry-widget\ we\ could\ use\ other\ widgets\ able\ to\ claim\ the\ selection.\nAmong\ standard\ widgets\ these\ are:\n\ \ \ *\ entry\n\ \ \ *\ listbox\n\ \ \ *\ text\nAn\ entry-widget\ has\ been\ choosen\ just\ because\ it\ is\ the\ simpler\ widget.\nAnyway,\ the\ solution\ (the\ enhanced\ listbox)\ is\ independent\ of,\ or\nbetter,\ is\ unaware\ of,\ the\ 'other'\ widgets\ that\ could\ claim\ the\nselection.\n\n\nIt\ is\ important\ to\ remark\ here\ that\ a\ selection\ in\ a\ listbox\ could\ change\nfor\ two\ kind\ of\ reasons:\n\ \ \ *\ in\ response\ to\ changes\ made\ by\ a\ PROGRAM\n\ \ \ *\ in\ response\ to\ changes\ made\ by\ a\ USER\n\nIt\ is\ a\ common\ and\ well-documented\ tecnique\ to\ intercept\ USER\ changes,\ by\nproviding\ a\ callback\ for\ the\ <<ListboxSelect>>\ event.\ This\ technique\ is\nnot\ totally\ perfect\ (as\ you\ will\ see\ later)\ but,\ more\ important,\ this\ntechnique\ cannot\ be\ used\ for\ intercepting\ changes\ made\ by\ a\ PROGRAM.\n\nWhat\ I\ want\ to\ say\ is\ that,\ when\ a\ PROGRAM\ changes\ the\ selection\ in\ a\ listbox,\ e.g.\n\ #\ select\ the\ first\ row\ in\ a\ listbox\ \$lb\n\ \$lb\ select\ set\ 0\ \ \n\ #\ delete\ the\ first\ row\n\ \$lb\ delete\ 0\n'''NO'''\ <<ListboxSelect>>\ event\ is\ generated.\nI\nn\ these\ cases\ it\ is\ the\ programmer's\ responsability\ add\ some\ code\nenabling/disabling\ the\ 'related\ button'.\n\n''a\ simple\ solution\ I\ recommend\ for\ these\ cases\ is\ the\ following:\n\ \ if\ you\ have\ some\ code\ that\ *may*\ change\ the\ selection\ in\ a\ listbox,\n\ \ simply\ generate\ a\ virtual\ event\ after.''\nE.g\n\ \ \ \ ...\n\ \ \ \ \$lb\ selection\ clear\ 0\ end\n\ \ \ \ ...\n\ \ \ should\ be\ written\ as\n\ \ \ \ ...\n\ \ \ \ \$lb\ selection\ clear\ 0\ end\n\ \ \ \ event\ generate\ \$lb\ <<ListboxSelect>>\n\ \ \ \ ...\n\nThe\ other\ case,\ when\ the\ selection\ changes\ in\ response\ to\ changes\ made\ by\na\ USER,\ is\ more\ complex\ ...\n\nOf\ course\ the\ application\ cannot\ wait\ for\ user\ changes\;\ some\ tecniques\nfor\ controlling\ the\ event-loop\ are\ required\ ...\n\nI\ will\ show\ you\ how\ to\ provide\ an\ handler\ to\ deal\ with\ ALL\ changes\ made\ by\nthe\ USER.\n\n------\n\nAfter\ these\ long\ premise,\ we\ are\ ready\ for\ the\ solution.\n\nThe\ solution\ is\ based\ on\ the\ following\ principles:\n\n'''(A)\ intercept\ all\ the\ <<ListboxSelect>>\ generated\ events.'''\n\n\nThis\ way\ allows\ you\ to\ know\ when\ a\ user\ selects\ an\ element\ of\ the\ listbox\ and\n(if\ \"-selectmode\"\ option\ is\ \"multiple\"\ or\ \"extended\")\ when\ a\ user\ndeselects\ the\ last\ element.\n\nbind\ \$lb\ <<ListboxSelect>>\ \[list\ ::cb_selectionChanged\ %W\]\ \n\nproc\ ::cb_selectionChanged\ \{w\ args\}\ \{\n\ \ if\ \{\ \[\$w\ curselection\]\ ==\ \"\"\ \}\ \{\n\ \ \ \ \ #\ listbox\ has\ no\ selected\ items\n\ \ \}\ else\ \{\n\ \ \ \ \ #\ listbox\ has\ one\ or\ more\ selected\ items\n\ \ \}\n\nUnfortunately\ there\ is\ lack\;\ if\ user\ makes\ a\ selection\ in\ another\ widget\n(e.g\ an\ entry-widget),\ all\ the\ selected\ elements\ of\ the\ listbox\ndisappear,\ and\ worst,\ NO\ event\ is\ generated.\n\nNOTE:\ when\ user\ clicks-in\ an\ entry-widget,\ or\ he\ enters\ some\ text,\nnothing\ happens\ to\ the\ listbox\;\ it\ is\ only\ when\ the\ user\ *selects*\ some\ntext\ in\ an\ entry-widget\ that\ the\ listbox\ loses\ all\ its\ selected\ items\n(provided\ that\ listbox\ option\ \"-exportselection\"\ is\ \"1\"\ (default))\n\n(B)\ register\ a\ callback\ so\ that\ listbox\ will\ be\ notified\ when\ another\nwidget\ claims\ the\ selection.\n\n(indenta)\nNote\ that\ there\ can\ be\ only\ one\ widget\ registered\ for\ this\ notification,\nand\ this\ widget\ should\ be\ the\ widget\ currently\ owning\ the\ selection.\nTherefore,\ each\ time\ a\ listbox\ widget\ (you\ could\ have\ more\ than\ one)\ gets\nthe\ selection,\ it\ should\ register\ itself\ for\ this\ kind\ of\ notification.\nFortunately,\ this\ is\ easy,\ because\ each\ time\ the\ <<ListboxSelect>>\ event\nis\ generated,\ (see\ above),\ it\ means\ that\ THAT\ listbox\ has\ got\ the\nselection.\nAll\ we\ need\ to\ add\ is\ the\ following\n\n\ ##\ ----------------------------------------------------------------\n\ ##\ generic\ code\ for\ enhanced\ listbox\n\ ##\ ----------------------------------------------------------------\n\ \n\ \n\ \ #\ define\ an\ event-handler\ valid\ for\ the\ whole\ 'Listbox'\ class\nbind\ Listbox\ <<ListboxSelect>>\ \[list\ gotSelectEvent\ %W\]\n\nproc\ gotSelectEvent\ \{w\}\ \{\n\ \ \ puts\ \"Listbox-class\ received\ <<ListboxSelect>>\"\n\ \ \ if\ \{\ \[\$w\ curselection\]\ !=\ \"\"\ \ &&\ \ \[\$w\ cget\ -exportselection\]\ ==\ 1\ \}\ \{\n\ \ \ \ \ \ \ \ \ selection\ own\ -command\ \[list\ lostSelection\ \$w\]\ \$w\n\ \ \ \}\ \n\}\n\nproc\ lostSelection\ \{w\}\ \{\n\ \ \ if\ \{\ \[\$w\ cget\ -exportselection\]\ ==\ 1\ \}\ \{\n\ \ \ \ \ \ puts\ \"Listbox\ \$w\ lost\ selection\"\n\ \ \ \ \ \ \$w\ selection\ clear\ 0\ end\n\ \ \ \ \ \ event\ generate\ \$w\ <<ListboxSelect>>\n\ \ \ \}\n\}\n\nNote\ that\ I\ wrote\ anything\ tied\ to\ a\ 'particular'\ listbox\ instance,\ nor\ a\n'particular'\ event-handler\ for\ a\ <<ListboxSelect>>\ tied\ to\ a\ listbox.\nThere's\ only\ an\ event-handler\ valid\ for\ ALL\ listboxes.\ Particular\ninstances\ of\ listbox\ can\ (should)\ write\ their\ own\ peculiar\ event-handler.\nSomething\ like\ this:\n\n====\n\ #\ remember\ you\ MUST\ load\ the\ above\ 'generic\ code\ for\ enhanced\ listbox'\n...\n\ \ #\ purpose\ of\ this\ proc\ is\ to\ enable/disable\ the\ button\ \$b\n\ \ #\ \ depending\ on\ the\ selected\ rows\ of\ the\ listbox\ \$lb\nproc\ MY_selectHandler\ \{lb\ b\}\ \{\n\ \ \ if\ \{\ \[\$lb\ curselection\]\ ==\ \"\"\ \}\ \{\n\ \ \ \ \ \ \$b\ configure\ -state\ disabled\n\ \ \ \}\ else\ \{\n\ \ \ \ \ \ \$b\ configure\ -state\ normal\n\ \ \ \}\n\}\n\nlistbox\ .lb\nbutton\ .b\ -state\ disabled\ -text\ \"button\ related\ to\ listbox\"\ \npack\ .lb\ .b\nbind\ .lb\ <<ListboxSelect>>\ \[list\ MY_selectHandler\ .lb\ .b\]\n\n...\n\n\nAnd\ now,\ here\ is\ a\ complete\ example.\ experiment\ it\ !\n\n====\n\n\ ##\ ----------------------------------------------------------------\n\ ##\ generic\ code\ for\ enhanced\ listbox\n\ ##\ ----------------------------------------------------------------\n\ \n\ \n\ \ #\ define\ an\ event-handler\ valid\ for\ the\ whole\ 'Listbox'\ class\nbind\ Listbox\ <<ListboxSelect>>\ \[list\ gotSelectEvent\ %W\]\n\nproc\ gotSelectEvent\ \{w\}\ \{\n\ \ \ puts\ \"Listbox-class\ received\ <<ListboxSelect>>\"\n\ \ \ if\ \{\ \[\$w\ curselection\]\ !=\ \"\"\ \ &&\ \ \[\$w\ cget\ -exportselection\]\ ==\ 1\ \}\ \{\n\ \ \ \ \ \ \ \ \ selection\ own\ -command\ \[list\ lostSelection\ \$w\]\ \$w\n\ \ \ \}\ \n\}\n\nproc\ lostSelection\ \{w\}\ \{\n\ \ \ if\ \{\ \[\$w\ cget\ -exportselection\]\ ==\ 1\ \}\ \{\n\ \ \ \ \ \ puts\ \"Listbox\ \$w\ lost\ selection\"\n\ \ \ \ \ \ \$w\ selection\ clear\ 0\ end\n\ \ \ \ \ \ event\ generate\ \$w\ <<ListboxSelect>>\n\ \ \ \}\n\}\n\n\ ##\ ----------------------------------------------------------------\n\ ##\ sample\ code\ for\ testing\ ....\n\ ##\ ----------------------------------------------------------------\n\n\ \ #\ define\ here\ a\ proc\ for\ creating\ a\ listbox\ with\ a\ related-button\n\ \ #\ \ plus\ some\ checkbuttons/radiobuttons\ for\ changing\ its\ properties\ \ \nproc\ myComplexListbox\ \{w\}\ \{\n\ \ \ frame\ \$w\ -relief\ raised\ -bd\ 2\ -padx\ 5\ -pady\ 5\n\n\ \ \ \ #\ create\ a\ listbox\;\ it\ is\ an\ enhnaced\ listbox\ thanks\ to\ the\n\ \ \ \ #\ \ extended\ Listbox-class\ handler\ defined\ above\n\ \ \ listbox\ \$w.lb\n\ \ \ button\ \$w.b\ -text\ \"apply\ on\ selected\ item\"\ \\\n\ \ \ \ \ \ -command\ \[list\ showSelected\ \$w.lb\]\n\ \ \ \$w.b\ configure\ -state\ disabled\n\ \ \ pack\ \$w.lb\ \$w.b\n\ \ \ \ #\ bind\ event\ to\ a\ custom\ handler\ (enabling/disabling\ related\ button)\n\ \ \ bind\ \$w.lb\ <<ListboxSelect>>\ \[list\ mySelectHandler\ \$w\]\n\n\n\ \ \ \ #\ other\ controls\ ...\n\ \ \ \ \n\ \ \ set\ ::control(\$w,mode)\ browse\n\ \ \ foreach\ mode\ \{single\ browse\ extended\ multiple\}\ \{\n\ \ \ \ \ \ radiobutton\ \$w.rb_\$mode\ -value\ \$mode\ -variable\ ::control(\$w,mode)\ \\\n\ \ \ \ \ \ \ \ -text\ \$mode\ \\\n\ \ \ \ \ \ \ \ -command\ \[list\ \$w.lb\ configure\ -selectmode\ \$mode\]\n\ \ \ \ \ \ pack\ \$w.rb_\$mode\n\ \ \ \}\n\ \ \ \ \ \n\ \ \ set\ ::control(\$w,exportselection)\ 1\n\ \ \ checkbutton\ \$w.expsel\ -text\ \"-exportselection\"\ \\\n\ \ \ \ \ \ -variable\ ::control(\$w,exportselection)\ \\\n\ \ \ \ \ \ -command\ \[list\ setExportSelection\ \$w\]\n\ \ \ pack\ \$w.expsel\n\ \ \ return\ \$w\n\}\n\nproc\ showSelected\ \{lb\}\ \{\n\ \ \ puts\ \"selected\ element\ is\ <\[\$lb\ curselection\]>\"\n\}\n\nproc\ setExportSelection\ \{w\}\ \{\n\ \ \$w.lb\ configure\ -exportselection\ \$::control(\$w,exportselection)\n\}\ \n\n\nproc\ mySelectHandler\ \{w\}\ \{\n\ \ puts\ \"<\$w.lb>\ received\ <<ListboxSelect>>\"\n\ \ \ #\ note\ that\ if\ -selectmode\ is\ multiple/extended,\ and\ the\ last\ item\n\ \ \ #\ \ is\ deselected,\ then\ <<ListboxSelect>>\ is\ generated\ !\n\ \ \ \n\ \ if\ \{\ \[\$w.lb\ curselection\]\ !=\ \"\"\ \}\ \{\n\ \ \ \ \ \$w.b\ configure\ -state\ normal\ \ \ \n\ \ \}\ else\ \{\n\ \ \ \ \ \$w.b\ configure\ -state\ disabled\n\ \ \}\n\}\n\n\npack\ \[myComplexListbox\ .m1\]\n.m1.lb\ insert\ 0\ aa\ bb\ cc\ dd\npack\ \[myComplexListbox\ .m2\]\n.m2.lb\ insert\ 0\ xx\ yy\ zz\n\n\ #\ some\ 'other'\ standard\ widgets\ that\ could\ claim\ the\ selection\ ...\npack\ \[labelframe\ .other\ -text\ \"other\ widgets..\"\ -padx\ 5\ -pady\ 5\]\npack\ \[entry\ .other.e1\]\npack\ \[entry\ .other.e2\]\n\n====\n\nAs\ a\ final\ exercise\ I\ rewrote\ the\ same\ solution\ in\ a\ 00-way\ using\ Snit.\nThis\ latter\ solution\ is\ more\ elegant,\ providing\ a\ new\ widget\ \"extListbox\"\nhiding\ all\ the\ internal\ details,\ without\ the\ need\ to\ occupy\ an\ event\nhandler\ for\ the\ Listbox\ class.\nHere\ is\ the\ 'generic'\ Snit\ code\ providing\ the\ new\ \"extListBox\"\ widget\n====\npackage\ require\ snit\ 0.97\n\n::snit::widgetadaptor\ extListbox\ \{\n\ \ \ \n\ \ \ option\ -exportselection\ 1\n\n\ \ \ delegate\ method\ *\ to\ hull\n\ \ \ delegate\ option\ *\ to\ hull\ except\ \{\ -exportselection\ \}\ \n\n\ \ \ \ #define\ a\ 'pseudo'\ Class\ binding\n\ \ \ typeconstructor\ \{\n\ \ \ \ \ \ bind\ ExtListbox\ <<ListboxSelect>>\ \[myproc\ gotListboxSelect\ %W\]\n\ \ \ \}\n\n\n\ \ \ constructor\ \{args\}\ \{\n\ \ \ \ \ \ installhull\ using\ listbox\n\ \ \ \ \ \ \$self\ configurelist\ \$args\n\ \ \ \ \ \ bindtags\ \$win\ \[linsert\ \[bindtags\ \$win\]\ 1\ ExtListbox\]\n\ \ \ \}\n\ \ \ \n\n\ \ \ \ \ \ #\ intercept\ option\ -exportselection.\n\ \ \ onconfigure\ -exportselection\ \{value\}\ \{\n\ \ \ \ \ \ \$hull\ configure\ -exportselection\ \$value\n\ \ \ \ \ \ set\ options(-exportselection)\ \$value\n\ \ \ \ \ \ if\ \{\ \$value\ &&\ \ \[\$win\ curselection\]\ !=\ \"\"\ \}\ \{\ \n\ \ \ \ \ \ \ \ \ selection\ own\ -command\ \[myproc\ lostSelection\ \$win\]\ \$win\n\ \ \ \ \ \ \}\ \ \ \ \ \ \n\ \ \ \}\n\n\n\ \ \ proc\ gotListboxSelect\ \{w\}\ \{\n\ \ \ \ \ \ if\ \{\ \[\$w\ curselection\]\ !=\ \"\"\ \ &&\ \ \[\$w\ cget\ -exportselection\]\ ==\ 1\ \}\ \{\n\ \ \ \ \ \ \ \ \ selection\ own\ -command\ \[myproc\ lostSelection\ \$w\]\ \$w\n\ \ \ \ \ \ \}\ \n\ \ \ \}\n\n\ \ \ proc\ lostSelection\ \{w\}\ \{\n\ \ \ \ \ \ if\ \{\ \[\$w\ cget\ -exportselection\]\ ==\ 1\ \}\ \{\n\ \ \ \ \ \ \ \ \ \$w\ selection\ clear\ 0\ end\n\ \ \ \ \ \ \ \ \ event\ generate\ \$w\ <<ListboxSelect>>\n\ \ \ \ \ \ \}\n\ \ \ \}\n\}\n====\n\nand\ here\ is\ the\ code\ for\ testing.\n\n======\n\n\ #\ NOTE:\ Snit-widget\ extListbox\ is\ required\n\nproc\ user_gotListboxSelect\ \{w\}\ \{\n\ \ puts\ \"<\$w.lb>\ received\ <<ListboxSelect>>\"\n\ \ \ #\ note\ that\ if\ -selectmode\ is\ multiple/extended,\ and\ the\ last\ item\n\ \ \ #\ \ is\ deselected,\ then\ <<ListboxSelect>>\ is\ generated\ !\n\ \ \ \n\ \ if\ \{\ \[\$w.lb\ curselection\]\ !=\ \"\"\ \}\ \{\n\ \ \ \ \ \$w.b\ configure\ -state\ normal\ \ \ \n\ \ \}\ else\ \{\n\ \ \ \ \ \$w.b\ configure\ -state\ disabled\n\ \ \}\n\n\}\n\nproc\ user_showSelected\ \{lb\}\ \{\n\ \ \ puts\ \"selected\ element\ is\ <\[\$lb\ curselection\]>\"\n\}\n\nproc\ user_setExportSelection\ \{w\}\ \{\n\ \ \$w.lb\ configure\ -exportselection\ \$::control(\$w,exportselection)\n\}\ \n\nproc\ myComplexListbox\ \{w\}\ \{\n\ \ \ frame\ \$w\ -relief\ raised\ -bd\ 2\ -padx\ 5\ -pady\ 5\n\n\ \ \ extListbox\ \$w.lb\n\ \ \ button\ \$w.b\ -text\ \"apply\ on\ selected\ item\"\ \\\n\ \ \ \ \ \ -command\ \[list\ user_showSelected\ \$w.lb\]\n\ \ \ \$w.b\ configure\ -state\ disabled\n\ \ \ pack\ \$w.lb\ \$w.b\n\ \ \ \n\ \ \ bind\ \$w.lb\ <<ListboxSelect>>\ \[list\ user_gotListboxSelect\ \$w\]\n\n\n\ \ \ \ #\ other\ controls\ ...\n\ \ \ \ \n\ \ \ set\ ::control(\$w,mode)\ browse\n\ \ \ foreach\ mode\ \{single\ browse\ extended\ multiple\}\ \{\n\ \ \ \ \ \ radiobutton\ \$w.rb_\$mode\ -value\ \$mode\ -variable\ ::control(\$w,mode)\ -text\ \$mode\ \\\n\ \ \ \ \ \ \ \ -command\ \[list\ \$w.lb\ configure\ -selectmode\ \$mode\]\n\ \ \ \ \ \ pack\ \$w.rb_\$mode\n\ \ \ \}\n\ \ \ \ \ \n\ \ \ set\ ::control(\$w,exportselection)\ 1\n\ \ \ checkbutton\ \$w.expsel\ -text\ \"-exportselection\"\ \\\n\ \ \ \ \ \ -variable\ ::control(\$w,exportselection)\ \\\n\ \ \ \ \ \ -command\ \[list\ user_setExportSelection\ \$w\ \]\n\ \ \ pack\ \$w.expsel\n\ \ \ return\ \$w\n\}\n\n\n\npack\ \[myComplexListbox\ .m1\]\n.m1.lb\ insert\ 0\ aa\ bb\ cc\ dd\npack\ \[myComplexListbox\ .m2\]\n.m2.lb\ insert\ 0\ xx\ yy\ zz\n\npack\ \[labelframe\ .other\ -text\ \"other\ widgets..\"\ -padx\ 5\ -pady\ 5\]\npack\ \[entry\ .other.e1\]\npack\ \[entry\ .other.e2\]\n\n----\n\nWhat's\ next\ ?\n\nWell,\ I\ think\ this\ exercise\ can\ be\ generalized\ for\ other\ standard\nwidgets,\ such\ as\ text-widget\ and\ tablelist.\n\nBut\ the\ better\ things\ will\ be\ this\ idea\ be\ incorporated\ in\ the\ standard\nlistbox\ widget\ ...} CALL {my revision {How to totally handle listbox selection}} CALL {::oo::Obj2679071 process revision/How+to+totally+handle+listbox+selection} CALL {::oo::Obj2679069 process}

-errorcode

NONE

-errorinfo

Unknow state transition: LINE -> END
    while executing
"error $msg"
    (class "::Wiki" method "render_wikit" line 6)
    invoked from within
"my render_$default_markup $N $C $mkup_rendering_engine"
    (class "::Wiki" method "render" line 8)
    invoked from within
"my render $name $C"
    (class "::Wiki" method "revision" line 31)
    invoked from within
"my revision $page"
    (class "::Wiki" method "process" line 56)
    invoked from within
"$server process [string trim $uri /]"

-errorline

4