Re: Extend selection in ttk.Treeview

Vasilis Vlachoudis <[email protected]> Wed, 6 Jan 2021 09:57:57 +0000
Newsgroups gmane.comp.python.tkinter
Message-ID <[email protected]>
--===============6332587465758679377==
Content-Language: en-US
Content-Type: multipart/alternative;
	boundary="_000_0BC70B5D93E054469872FFD0FE07220E0312E0A6C9CERNXCHG51cer_"

--_000_0BC70B5D93E054469872FFD0FE07220E0312E0A6C9CERNXCHG51cer_
Content-Type: text/plain; charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

For the moment I came up with this solution, which seems to work,
however I am not very happy with it.
I need to define an "anchor" variable to remember from where the selection =
started

class MyTreeview(ttk.Treeview):
   def __init__(self, master, *kw, **args):
      super().__init__(master, *kw, **args)
      self.bind("<B1-Motion>", self.b1motion)
      self.bind("<ButtonRelease-1>", self.release)
      self.bind("<Up>",self.up)
      self.bind("<Down>", self.down)
      self.bind("<Shift-Key-Up>", self.selectUp)
      self.bind("<Shift-Key-Down>",self.selectDown)
      self._anchor =3D ""

   # ----------------------------------------------------------------------
   def b1motion(self, event):
      # If selected item is the last one focused
      # then ignore, otherwise Select is selecting everything
      if self.identify_row(event.y) =3D=3D self.focus(): return
      self.tk.call("ttk::treeview::Select", self._w, event.x, event.y, "ext=
end")

   # ----------------------------------------------------------------------
   def release(self, event):
      self.tk.call("ttk::treeview::Release", self._w, event.x, event.y)
      self._anchor =3D self.focus()
      return "break"

   # ----------------------------------------------------------------------
   def up(self, event):
      self.tk.call("ttk::treeview::Keynav", self._w, "up")
      self._anchor =3D self.focus()
      return "break"

   # ----------------------------------------------------------------------
   def down(self, event):
      self.tk.call("ttk::treeview::Keynav", self._w, "down")
      self._anchor =3D self.focus()
      return "break"

   # ----------------------------------------------------------------------
   def selectUp(self, event):
      if not self._anchor: self._anchor =3D self.focus()
      self.tk.call("ttk::treeview::Keynav", self._w, "up")
      if self.focus() !=3D self._anchor:
            self.tk.call("ttk::treeview::SelectOp", self._w, self._anchor, =
"extend")
      return "break"

   # ----------------------------------------------------------------------
   def selectDown(self, event):
      if not self._anchor: self._anchor =3D self.focus()
      self.tk.call("ttk::treeview::Keynav", self._w, "down")
      if self.focus() !=3D self._anchor:
            self.tk.call("ttk::treeview::SelectOp", self._w, self._anchor, =
"extend")
      return "break"

________________________________
From: Tkinter-discuss [tkinter-discuss-bounces+vasilis.vlachoudis=3Dcern.ch=
@python.org] on behalf of Vasilis Vlachoudis [[email protected]]
Sent: Tuesday, January 05, 2021 12:06
To: [email protected]
Subject: [Tkinter-discuss] Extend selection in ttk.Treeview

Hi all,

I am currently replacing some Listbox() with ttk.Treeview() however the Tre=
eview doesn't have the
"Shift-Up/Down" and "B1-Motion" capabilities to select with the keyboard mu=
ltiple items and with the mouse by click and drag.

Looking the treeview.tcl I've managed to add a binding for the B1-Motion wh=
ich seems to work,
however I failed to find a way to correctly replicate the Listbox behavior =
with the Shift-Up/Down
This is one of my failed tries

Any suggestion?

class MyTreeview(ttk.TreeView):
def __init__(self, master, *kw, **args):
super().__init__(master, *kw, **args)
self.bind("<B1-Motion>", self.b1motion)
self.bind("<Shift-Key-Up>", self.selectUp)
self.bind("<Shift-Key-Down>", self.selectDown)

def b1motion(self, event):
if self.identify_row(event.y) =3D=3D self.focus(): return
self.tk.call("ttk::treeview::Select", self._w, event.x, event.y, "extend")

def selectDown(self, event):
self.tk.call("ttk::treeview::Keynav", self._w, "down")
item =3D self.focus()
self.tk.call("ttk::treeview::SelectOp", self._w, item, "extend")
return "break"

--_000_0BC70B5D93E054469872FFD0FE07220E0312E0A6C9CERNXCHG51cer_
Content-Type: text/html; charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

<html dir=3D"ltr">
<head>
<meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3Diso-8859-=
1">
<style type=3D"text/css" id=3D"owaParaStyle"></style>
</head>
<body fpstyle=3D"1" ocsi=3D"0">
<div style=3D"direction: ltr;font-family: Tahoma;color: #000000;font-size: =
10pt;">
<div style=3D"direction:ltr; font-family:Tahoma; color:#000000; font-size:1=
0pt">
<div><span style=3D"font-size:13.3333px">For the moment I came up with this=
 solution, which seems to work,</span></div>
<div><span style=3D"font-size:13.3333px">however I am not very happy with i=
t.</span></div>
<div><span style=3D"font-size:13.3333px">I need to define an &quot;anchor&q=
uot; variable to remember from where the selection started</span></div>
<div><span style=3D"font-size:13.3333px"><br>
</span></div>
<div><span style=3D"font-size:13.3333px">class MyTreeview(ttk.Treeview):</s=
pan></div>
<div><span style=3D"font-size:13.3333px"><span style=3D"white-space:pre"></=
span>&nbsp; &nbsp;def __init__(self, master, *kw, **args):</span></div>
<div><span style=3D"font-size:13.3333px"><span style=3D"white-space:pre"></=
span>&nbsp; &nbsp; &nbsp; super().__init__(master, *kw, **args)</span></div=
>
<div><span style=3D"white-space:pre"></span><span style=3D"font-size: 10pt;=
">&nbsp; &nbsp; &nbsp;</span><span style=3D"font-size: 10pt;">&nbsp;</span>=
self.bind(&quot;&lt;B1-Motion&gt;&quot;,&nbsp;self.b1motion)</div>
<div><span style=3D"font-size:13.3333px"><span style=3D"white-space:pre"></=
span>&nbsp; &nbsp; &nbsp; self.bind(&quot;&lt;ButtonRelease-1&gt;&quot;,&nb=
sp;self.release)</span></div>
<div><span style=3D"font-size: 10pt;">&nbsp; &nbsp; &nbsp;</span><span styl=
e=3D"font-size: 10pt;">&nbsp;</span><span style=3D"font-size:13.3333px"><sp=
an style=3D"white-space:pre"></span>self.bind(&quot;&lt;Up&gt;&quot;,self.u=
p)</span></div>
<div><span style=3D"font-size: 10pt;">&nbsp; &nbsp; &nbsp;</span><span styl=
e=3D"font-size: 10pt;">&nbsp;</span><span style=3D"font-size:13.3333px"><sp=
an style=3D"white-space:pre"></span>self.bind(&quot;&lt;Down&gt;&quot;,<spa=
n style=3D"white-space: pre;">
</span>self.down)</span></div>
<div><span style=3D"font-size: 10pt;">&nbsp; &nbsp; &nbsp;</span><span styl=
e=3D"font-size: 10pt;">&nbsp;</span><span style=3D"font-size:13.3333px"><sp=
an style=3D"white-space:pre"></span>self.bind(&quot;&lt;Shift-Key-Up&gt;&qu=
ot;,<span style=3D"white-space: pre;">
</span>self.selectUp)</span></div>
<div><span style=3D"font-size: 10pt;">&nbsp; &nbsp; &nbsp;</span><span styl=
e=3D"font-size: 10pt;">&nbsp;</span><span style=3D"font-size:13.3333px"><sp=
an style=3D"white-space:pre"></span>self.bind(&quot;&lt;Shift-Key-Down&gt;&=
quot;,self.selectDown)</span></div>
<div><span style=3D"font-size: 10pt;">&nbsp; &nbsp; &nbsp;</span><span styl=
e=3D"font-size: 10pt;">&nbsp;</span><span style=3D"font-size:13.3333px"><sp=
an style=3D"white-space:pre"></span>self._anchor =3D &quot;&quot;</span></d=
iv>
<div><span style=3D"font-size:13.3333px"><br>
</span></div>
<div><span style=3D"font-size:13.3333px">&nbsp; &nbsp;# -------------------=
---------------------------------------------------</span></div>
<div><span style=3D"white-space:pre"></span><span style=3D"font-size: 10pt;=
">&nbsp; </span>
<span style=3D"font-size: 10pt;">&nbsp;</span>def b1motion(self, event):</d=
iv>
<div><span style=3D"font-size: 10pt;">&nbsp; &nbsp; &nbsp;</span><span styl=
e=3D"font-size: 10pt;">&nbsp;</span><span style=3D"font-size:13.3333px"><sp=
an style=3D"white-space:pre"></span># If selected item is the last one focu=
sed</span></div>
<div><span style=3D"font-size: 10pt;">&nbsp; &nbsp; &nbsp;</span><span styl=
e=3D"font-size: 10pt;">&nbsp;</span><span style=3D"font-size:13.3333px"><sp=
an style=3D"white-space:pre"></span># then ignore, otherwise Select is sele=
cting everything</span></div>
<div><span style=3D"font-size: 10pt;">&nbsp; &nbsp; &nbsp;</span><span styl=
e=3D"font-size: 10pt;">&nbsp;</span><span style=3D"font-size:13.3333px"><sp=
an style=3D"white-space:pre"></span>if&nbsp;</span>self.identify_row(event.=
y) =3D=3D self.focus(): return</div>
<div><span style=3D"font-size: 10pt;">&nbsp; &nbsp; &nbsp;</span><span styl=
e=3D"font-size: 10pt;">&nbsp;</span><span style=3D"font-size:13.3333px"><sp=
an style=3D"white-space:pre"></span>self.tk.call(&quot;ttk::treeview::Selec=
t&quot;, self._w, event.x, event.y, &quot;extend&quot;)</span></div>
<div><span style=3D"font-size:13.3333px"><br>
</span></div>
<div><span style=3D"font-size:13.3333px"><span style=3D"white-space:pre"></=
span>&nbsp; &nbsp;# -------------------------------------------------------=
---------------</span></div>
<div><span style=3D"font-size:13.3333px"><span style=3D"white-space:pre"></=
span>&nbsp; &nbsp;def release(self, event):</span></div>
<div><span style=3D"font-size: 10pt;">&nbsp; &nbsp; &nbsp;</span><span styl=
e=3D"font-size: 10pt;">&nbsp;</span><span style=3D"font-size:13.3333px"><sp=
an style=3D"white-space:pre"></span>self.tk.call(&quot;ttk::treeview::Relea=
se&quot;, self._w, event.x, event.y)</span></div>
<div><span style=3D"font-size: 10pt;">&nbsp; &nbsp; &nbsp;</span><span styl=
e=3D"font-size: 10pt;">&nbsp;</span><span style=3D"font-size:13.3333px"><sp=
an style=3D"white-space:pre"></span>self._anchor =3D self.focus()</span></d=
iv>
<div><span style=3D"font-size: 10pt;">&nbsp; &nbsp; &nbsp;</span><span styl=
e=3D"font-size: 10pt;">&nbsp;</span><span style=3D"font-size:13.3333px"><sp=
an style=3D"white-space:pre"></span>return &quot;break&quot;</span></div>
<div><span style=3D"font-size:13.3333px"><br>
</span></div>
<div><span style=3D"font-size:13.3333px"><span style=3D"white-space:pre"></=
span>&nbsp; &nbsp;# -------------------------------------------------------=
---------------</span></div>
<div><span style=3D"font-size:13.3333px"><span style=3D"white-space:pre"></=
span>&nbsp; &nbsp;def up(self, event):</span></div>
<div><span style=3D"font-size: 10pt;">&nbsp; &nbsp; &nbsp;</span><span styl=
e=3D"font-size: 10pt;">&nbsp;</span><span style=3D"font-size:13.3333px"><sp=
an style=3D"white-space:pre"></span>self.tk.call(&quot;ttk::treeview::Keyna=
v&quot;, self._w, &quot;up&quot;)</span></div>
<div><span style=3D"font-size: 10pt;">&nbsp; &nbsp; &nbsp;</span><span styl=
e=3D"font-size: 10pt;">&nbsp;</span><span style=3D"font-size:13.3333px"><sp=
an style=3D"white-space:pre"></span>self._anchor =3D self.focus()</span></d=
iv>
<div><span style=3D"font-size: 10pt;">&nbsp; &nbsp; &nbsp;</span><span styl=
e=3D"font-size: 10pt;">&nbsp;</span><span style=3D"font-size:13.3333px"><sp=
an style=3D"white-space:pre"></span>return &quot;break&quot;</span></div>
<div><span style=3D"font-size:13.3333px"><br>
</span></div>
<div><span style=3D"font-size:13.3333px"><span style=3D"white-space:pre"></=
span>&nbsp; &nbsp;# -------------------------------------------------------=
---------------</span></div>
<div><span style=3D"font-size:13.3333px"><span style=3D"white-space:pre"></=
span>&nbsp; &nbsp;def down(self, event):</span></div>
<div><span style=3D"font-size: 10pt;">&nbsp; &nbsp; &nbsp;</span><span styl=
e=3D"font-size: 10pt;">&nbsp;</span><span style=3D"font-size:13.3333px"><sp=
an style=3D"white-space:pre"></span>self.tk.call(&quot;ttk::treeview::Keyna=
v&quot;, self._w, &quot;down&quot;)</span></div>
<div><span style=3D"font-size: 10pt;">&nbsp; &nbsp; &nbsp;</span><span styl=
e=3D"font-size: 10pt;">&nbsp;</span><span style=3D"font-size:13.3333px"><sp=
an style=3D"white-space:pre"></span>self._anchor =3D self.focus()</span></d=
iv>
<div><span style=3D"font-size: 10pt;">&nbsp; &nbsp; &nbsp;</span><span styl=
e=3D"font-size: 10pt;">&nbsp;</span><span style=3D"font-size:13.3333px"><sp=
an style=3D"white-space:pre"></span>return &quot;break&quot;</span></div>
<div><span style=3D"font-size:13.3333px"><br>
</span></div>
<div><span style=3D"font-size:13.3333px"><span style=3D"white-space:pre"></=
span>&nbsp; &nbsp;# -------------------------------------------------------=
---------------</span></div>
<div><span style=3D"font-size:13.3333px"><span style=3D"white-space:pre"></=
span>&nbsp; &nbsp;def selectUp(self, event):</span></div>
<div><span style=3D"font-size: 10pt;">&nbsp; &nbsp; &nbsp;</span><span styl=
e=3D"font-size: 10pt;">&nbsp;</span><span style=3D"font-size:13.3333px"><sp=
an style=3D"white-space:pre"></span>if not self._anchor:&nbsp;</span>self._=
anchor =3D self.focus()</div>
<div><span style=3D"font-size: 10pt;">&nbsp; &nbsp; &nbsp;</span><span styl=
e=3D"font-size: 10pt;">&nbsp;</span><span style=3D"font-size:13.3333px"><sp=
an style=3D"white-space:pre"></span>self.tk.call(&quot;ttk::treeview::Keyna=
v&quot;, self._w, &quot;up&quot;)</span></div>
<div><span style=3D"font-size: 10pt;">&nbsp; &nbsp; &nbsp;</span><span styl=
e=3D"font-size: 10pt;">&nbsp;</span><span style=3D"font-size:13.3333px"><sp=
an style=3D"white-space:pre"></span>if self.focus() !=3D self._anchor:</spa=
n></div>
<div><span style=3D"font-size: 10pt;">&nbsp; &nbsp; &nbsp;</span><span styl=
e=3D"font-size: 10pt;">&nbsp;</span><span style=3D"font-size: 10pt;">&nbsp;=
 &nbsp; &nbsp;</span><span style=3D"font-size: 10pt;">&nbsp;</span>self.tk.=
call(&quot;ttk::treeview::SelectOp&quot;, self._w, self._anchor, &quot;exte=
nd&quot;)</div>
<div><span style=3D"font-size: 10pt;">&nbsp; &nbsp; &nbsp;</span><span styl=
e=3D"font-size: 10pt;">&nbsp;</span><span style=3D"font-size:13.3333px"><sp=
an style=3D"white-space:pre"></span>return &quot;break&quot;</span></div>
<div><span style=3D"font-size:13.3333px"><br>
</span></div>
<div><span style=3D"font-size:13.3333px"><span style=3D"white-space:pre"></=
span>&nbsp; &nbsp;# -------------------------------------------------------=
---------------</span></div>
<div><span style=3D"font-size:13.3333px"><span style=3D"white-space:pre"></=
span>&nbsp; &nbsp;def selectDown(self, event):</span></div>
<div><span style=3D"font-size: 10pt;">&nbsp; &nbsp; &nbsp;</span><span styl=
e=3D"font-size: 10pt;">&nbsp;</span><span style=3D"font-size:13.3333px"><sp=
an style=3D"white-space:pre"></span>if not self._anchor:</span><span style=
=3D"font-size: 10pt;">&nbsp;</span><span style=3D"font-size: 10pt;">self._a=
nchor
 =3D self.focus()</span></div>
<div><span style=3D"font-size: 10pt;">&nbsp; &nbsp; &nbsp;</span><span styl=
e=3D"font-size: 10pt;">&nbsp;</span><span style=3D"font-size:13.3333px"><sp=
an style=3D"white-space:pre"></span>self.tk.call(&quot;ttk::treeview::Keyna=
v&quot;, self._w, &quot;down&quot;)</span></div>
<div><span style=3D"font-size: 10pt;">&nbsp; &nbsp; &nbsp;</span><span styl=
e=3D"font-size: 10pt;">&nbsp;</span><span style=3D"font-size:13.3333px"><sp=
an style=3D"white-space:pre"></span>if self.focus() !=3D self._anchor:</spa=
n></div>
<div><span style=3D"font-size: 10pt;">&nbsp; &nbsp; &nbsp;</span><span styl=
e=3D"font-size: 10pt;">&nbsp;</span><span style=3D"font-size: 10pt;">&nbsp;=
 &nbsp; &nbsp;</span><span style=3D"font-size: 10pt;">&nbsp;</span>self.tk.=
call(&quot;ttk::treeview::SelectOp&quot;, self._w, self._anchor, &quot;exte=
nd&quot;)</div>
<div><span style=3D"font-size: 10pt;">&nbsp; &nbsp; &nbsp;</span><span styl=
e=3D"font-size: 10pt;">&nbsp;</span><span style=3D"font-size:13.3333px"><sp=
an style=3D"white-space:pre"></span>return &quot;break&quot;</span></div>
<div><br>
</div>
<div style=3D"font-family:Times New Roman; color:#000000; font-size:16px">
<hr tabindex=3D"-1">
<div id=3D"divRpF458632" style=3D"direction:ltr"><font face=3D"Tahoma" size=
=3D"2" color=3D"#000000"><b>From:</b> Tkinter-discuss [tkinter-discuss-boun=
ces&#43;[email protected]] on behalf of Vasilis Vlach=
oudis [[email protected]]<br>
<b>Sent:</b> Tuesday, January 05, 2021 12:06<br>
<b>To:</b> [email protected]<br>
<b>Subject:</b> [Tkinter-discuss] Extend selection in ttk.Treeview<br>
</font><br>
</div>
<div></div>
<div>
<div style=3D"direction:ltr; font-family:Tahoma; color:#000000; font-size:1=
0pt">Hi all,
<div><br>
</div>
<div>I am currently replacing some Listbox() with ttk.Treeview() however th=
e Treeview doesn't have the</div>
<div>&quot;Shift-Up/Down&quot; and &quot;B1-Motion&quot; capabilities to se=
lect with the keyboard multiple items and with the mouse by click and drag.=
</div>
<div><br>
</div>
<div>Looking the treeview.tcl I've managed to add a binding for the B1-Moti=
on which seems to work,</div>
<div>however I failed to find a way to correctly replicate the Listbox beha=
vior with the Shift-Up/Down</div>
<div>This is one of my failed tries</div>
<div><br>
</div>
<div>Any suggestion?</div>
<div><br>
</div>
<div>class MyTreeview(ttk.TreeView):</div>
<div><span style=3D"white-space:pre"></span>def __init__(self, master, *kw,=
 **args):</div>
<div>
<div><span style=3D"font-size:13.3333px"><span style=3D"white-space:pre"></=
span>super().__init__(master, *kw, **args)</span></div>
<div><span style=3D"white-space:pre"></span>self.bind(&quot;&lt;B1-Motion&g=
t;&quot;,<span style=3D"white-space:pre">
</span>self.b1motion)</div>
<div>
<div><span style=3D"white-space:pre"></span>self.bind(&quot;&lt;Shift-Key-U=
p&gt;&quot;,<span style=3D"white-space:pre">
</span>self.selectUp)</div>
<div><span style=3D"font-size:13.3333px"><span style=3D"white-space:pre"></=
span>self.bind(&quot;&lt;Shift-Key-Down&gt;&quot;,<span style=3D"white-spac=
e:pre">
</span>self.selectDown)</span></div>
</div>
<div><br>
</div>
</div>
<div><span style=3D"white-space:pre"></span>def b1motion(self, event):</div=
>
<div>
<div><span style=3D"font-size:13.3333px"><span style=3D"white-space:pre"></=
span>if self.identify_row(event.y) =3D=3D self.focus(): return</span></div>
<div><span style=3D"white-space:pre"></span>self.tk.call(&quot;ttk::treevie=
w::Select&quot;, self._w, event.x, event.y, &quot;extend&quot;)</div>
</div>
<div><br>
</div>
<div>
<div><span style=3D"white-space:pre"></span>def selectDown(self, event):</d=
iv>
<div><span style=3D"white-space:pre"></span>self.tk.call(&quot;ttk::treevie=
w::Keynav&quot;, self._w, &quot;down&quot;)</div>
<div><span style=3D"font-size:13.3333px"><span style=3D"white-space:pre"></=
span>item =3D self.focus()</span></div>
<div><span style=3D"white-space:pre"></span>self.tk.call(&quot;ttk::treevie=
w::SelectOp&quot;, self._w, item, &quot;extend&quot;)</div>
<div><span style=3D"font-size:13.3333px"><span style=3D"white-space:pre"></=
span>return &quot;break&quot;</span></div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>

--_000_0BC70B5D93E054469872FFD0FE07220E0312E0A6C9CERNXCHG51cer_--

--===============6332587465758679377==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
Tkinter-discuss mailing list
[email protected]
https://mail.python.org/mailman/listinfo/tkinter-discuss

--===============6332587465758679377==--