Keeping Selected Listbox Item through re-write

-1

I have a function that updates listbox entries by removing and re-inserting them with an updated counter, however difficulty arises when I try to maintain a highlighted item, as it has been removed there is nothing to highlight.

My question is how can I get the program to remember what was highlighted?

Code:

#!/usr/bin/python

from time            import clock, sleep
from os              import system
from collections     import defaultdict
from subprocess      import PIPE, Popen
from threading       import Thread, Lock

import Tkinter as tk
import Queue
import signal
import os, sys

# -------------------------------------------------------------------
#     Global Definitions

mydict ={}   # define the dictionary
dict_lock = Lock()
transList = []
running = 0
Counter = 0
edit_ref= 0
RecvQueue = Queue.Queue()
terminate = 0
pcanbus = "/dev/pcanusb0"

# ***************************************************************
#
# ************************   PCAM Msg    ************************ 
#
# ***************************************************************
class PCANmsg(object):

  def __init__(self):
    self.dlc        = 0
    self.CANtime    = 0
    self.PCANperiod = 0
    self.COUNT      = 0
    self.hdata0     = 0
    self.hdata1     = 0
    self.hdata2     = 0
    self.hdata3     = 0
    self.hdata4     = 0
    self.hdata5     = 0
    self.hdata6     = 0
    self.hdata7     = 0
    self.timing     = 0


class ThreadedTask(Thread):

    def __init__(self, queue):
        Thread.__init__(self)
        self.queue = queue

    def run(self):
        global proc
        payload = iter(proc.stdout.readline, "")
        for line in payload:
            if line[0].isdigit():
                splitline = line.split()
                self.dictAdd(splitline)


    def dictAdd(self, info):

        global mydict

        try:
            can_ID = info[4]

            p = PCANmsg()

            p.dlc        = int(info[5])
            p.CANtime    = float(info[0])
            p.hdata0     = info[6]  
            p.hdata1     = info[7]
            p.hdata2     = info[8]
            p.hdata3     = info[9]
            p.hdata4     = info[10]
            p.hdata5     = info[11]
            p.hdata6     = info[12]
            p.hdata7     = info[13]
            p.timing     = 1

            if can_ID in mydict.keys():
                q = mydict[can_ID]
                p.COUNT = q.COUNT + 1
                p.PCANperiod = p.CANtime - q.CANtime
            else:
                p.COUNT = 1
                p.PCANperiod = 0.0

            mydict[can_ID] = p

            s = '%06X : %3d   %02X %02X %02X %02X %02X %02X %02X %02X\t %8.2F %8d ' %\
                   (int(can_ID,16),
                    p.dlc,
                    int(p.hdata0, 16),
                    int(p.hdata1, 16),
                    int(p.hdata2, 16),
                    int(p.hdata3, 16),
                    int(p.hdata4, 16),
                    int(p.hdata5, 16),
                    int(p.hdata6, 16),
                    int(p.hdata7, 16),
                    p.PCANperiod,
                    p.COUNT)

            self.queue.put(s)
        except IndexError:
            pass

# ***************************************************************
#
# ************************ RecvTran GUI ************************* 
#
# ***************************************************************

class application:

    def __init__(self,window):

        self.window = window
    self.window.title("PYCAN")
        """Initialize the Application """

        window.grid_rowconfigure(9,weight=1)

        self.RecvButton = tk.Button(window,
                                    text = "Receive",
                                    command = self.RecvBtn_Click)
        self.RecvButton.grid(row = 9, column = 12)

        self.TransLabel = tk.Label(window, text = "Messages Received:")
        self.TransLabel.grid(row = 8, columnspan = 2)

        self.RecvList = tk.Listbox(window, height = 10, width = 60, exportselection=False)
        self.RecScrol = tk.Scrollbar(window)
        self.RecScrol.grid(row=9, column=11, sticky=tk.NW+tk.SE)
        self.RecvList.grid(row = 9, rowspan = 3, columnspan = 11, sticky=tk.NW+tk.SE)
        self.RecScrol.config(command=self.RecvList.yview)
        self.RecvList.config(yscrollcommand=self.RecScrol.set)
        self.RecvList.bind("<Button-1>", self.KeepSelection)

        self.QuitButton = tk.Button(window,
                                    text = 'Exit',
                                    command = QuitBtn_Click)
        self.QuitButton.grid(row = 14, column = 12)



    window.protocol("WM_DELETE_WINDOW", QuitBtn_Click)


    def KeepSelection(self, event):

    lb = event.widget
    selection = lb.curselection()
    value = lb.get(selection[0])
    print "%s" % value
    selected = int(value)
        self.lb.select_set(selected)

    def RecvBtn_Click(self, event=None):        

        global RecvQueue, Counter

        try:
            info = RecvQueue.get(0)
            info_split = info.split()

            if self.RecvList.size() <  len(mydict):

                #for _i in mydict.keys():
                for _i in sorted(mydict.keys()):
                    self.RecvList.insert("end",'%06X : %3d  %02X %02X %02X %02X %02X %02X %02X %02X   %8.1F   %8d ' %\
                       (int(_i,16),
                        mydict[_i].dlc,
                        int(mydict[_i].hdata0, 16),
                        int(mydict[_i].hdata1, 16),
                        int(mydict[_i].hdata2, 16),
                        int(mydict[_i].hdata3, 16),
                        int(mydict[_i].hdata4, 16),
                        int(mydict[_i].hdata5, 16),
                        int(mydict[_i].hdata6, 16),
                        int(mydict[_i].hdata7, 16),
                        mydict[_i].PCANperiod,
                        mydict[_i].COUNT))

            else:
                for i, listbox_entry in enumerate(self.RecvList.get(0, "end")):
                    list_split = listbox_entry.split()
                    if list_split[0] == info_split[0]:
            pos = self.RecScrol.get()
                        self.RecvList.delete(i)
                        self.RecvList.insert(i, info)
            self.RecvList.yview_moveto(pos[0])

                    else:
                        continue
                   #     self.RecvList.insert("end", info)
            self.window.after(20, self.RecvBtn_Click)

        Counter += 1

        if Counter > 25:
            with RecvQueue.mutex:
                RecvQueue.queue.clear()
                Counter = 0

        except Queue.Empty:
            self.window.after(50, self.RecvBtn_Click)


def QuitBtn_Click(event=None):
    global terminate
    global proc

    terminate = 1

    try:
        if terminate == 1:
            os.kill(proc.pid, 0)
            proc.kill()
        root.destroy()    
    except OSError, e:
        print "terminated Gracefully"


# ***************************************************************
#
# ************************ Script Start  ************************ 
#
# ***************************************************************
if __name__ == "__main__":

    try:
        proc = Popen(("receivetest -f=%s" % pcanbus).split(), stdout = PIPE)
    except OSError:
        print "ERROR ESTABLISHING CONNECTION"

    DataStream = ThreadedTask(RecvQueue)
    DataStream.daemon = True
    DataStream.start()

    root = tk.Tk()

    myapp = application(root)
    root.mainloop()

# --------------------------------------------------------------

Hoepfully you can see what I am trying to do. My Selection method doesn't work because the index is removed and thus has nothing to map to.

Data that would be expected:

12106694.169 receivetest: m s 0x0000069a 8 00 00 00 00 00 0a 58 1a
12106694.638 receivetest: m s 0x0000069e 8 00 1f be 0f ea 0a 58 1a
12106695.107 receivetest: m s 0x00000663 8 2f 00 62 02 00 0a 58 1a
12106695.577 receivetest: m s 0x00000690 8 00 20 06 0f ea 0a 58 1a
12106794.137 receivetest: m s 0x0000069a 8 00 00 00 00 00 0a 58 1a
12106794.649 receivetest: m s 0x0000069e 8 00 1f be 0f ea 0a 58 1a
12106795.118 receivetest: m s 0x00000663 8 2f 00 62 02 00 0a 58 1a
12106795.587 receivetest: m s 0x00000690 8 00 20 06 0f ea 0a 58 1a
12106894.147 receivetest: m s 0x0000069a 8 00 00 00 00 00 0a 58 1a
12106894.617 receivetest: m s 0x0000069e 8 00 1f be 0f ea 0a 58 1a
12106895.86 receivetest: m s 0x00000663 8 2f 00 62 02 00 0a 58 1a
12106895.598 receivetest: m s 0x00000690 8 00 20 06 0f ea 0a 58 1a
12106994.158 receivetest: m s 0x0000069a 8 00 00 00 00 00 0a 58 1a
12106994.627 receivetest: m s 0x0000069e 8 00 1f be 0f ea 0a 58 1a
12106995.97 receivetest: m s 0x00000663 8 2f 00 62 02 00 0a 58 1a
12106995.566 receivetest: m s 0x00000690 8 00 20 06 0f ea 0a 58 1a
12107094.169 receivetest: m s 0x0000069a 8 00 00 00 00 00 0a 58 1a
12107094.638 receivetest: m s 0x00000663 8 2f 00 62 02 00 0a 58 1a
12107095.107 receivetest: m s 0x0000069e 8 00 1f be 0f ea 0a 58 1a
12107095.619 receivetest: m s 0x00000690 8 00 20 06 0f ea 0a 58 1a
12107194.179 receivetest: m s 0x0000069a 8 00 00 00 00 00 0a 58 1a
12107194.649 receivetest: m s 0x0000069e 8 00 1f be 0f ea 0a 58 1a
12107195.118 receivetest: m s 0x00000663 8 2f 00 62 02 00 0a 58 1a
12107195.587 receivetest: m s 0x00000690 8 00 20 06 0f ea 0a 58 1a
12107294.147 receivetest: m s 0x0000069a 8 00 00 00 00 00 0a 58 1a
12107294.659 receivetest: m s 0x0000069e 8 00 1f be 0f ea 0a 58 1a
12107295.129 receivetest: m s 0x00000663 8 2f 00 62 02 00 0a 58 1a
12107295.598 receivetest: m s 0x00000690 8 00 20 06 0f ea 0a 58 1a
12107394.158 receivetest: m s 0x0000069a 8 00 00 00 00 00 0a 58 1a
12107394.627 receivetest: m s 0x0000069e 8 00 1f be 0f ea 0a 58 1a
12107395.97 receivetest: m s 0x00000663 8 2f 00 62 02 00 0a 58 1a
12107395.566 receivetest: m s 0x00000690 8 00 20 06 0f ea 0a 58 1a
12107494.254 receivetest: m s 0x0000069a 8 00 00 00 00 00 0a 58 1a
12107494.766 receivetest: m s 0x00000690 8 00 20 06 00 00 0a 58 1a
12107495.235 receivetest: m s 0x00000691 8 01 1e 6e 4b 50 5a 06 00
12107495.662 receivetest: m s 0x00000663 8 2f 00 62 02 00 0a 58 1a

EDIT Created condensed working version of code

python
tkinter
listbox
asked on Stack Overflow May 22, 2015 by Jim • edited May 22, 2015 by Jim

1 Answer

3

All you have to do is get the index of the highlighted items, replace the data, and then re-select the highlighted items. If each item is unique, the process is extremely simple.

If the items are not unique, it's still possible. All you need to do is save the index of each selected item. When you delete something, remember the index of the item that was deleted. When restoring the selection, the indexes for items above the deleted item will be unchanged, and the indexes for the items below the one that was deleted need to subtract one (ie: if you delete item #5 and #10 was selected, after the delete you need to re-select #9)

Here is the solution for when you know the items in the listbox are unique.

First, this saves everything that was selected, by value:

def saveSelection(lb):
    selection = []
    for i in lb.curselection():
        selection.append(lb.get(i))
    return selection

Later, you can restore the selected items with this:

def restoreSelection(lb, selectedItems):
    lb.selection_clear(0, "end")
    items = lb.get(0, "end")
    for item in selectedItems:
        if item in items:
            index = items.index(item)
            lb.selection_set(index)
answered on Stack Overflow May 22, 2015 by Bryan Oakley • edited May 22, 2015 by Bryan Oakley

User contributions licensed under CC BY-SA 3.0