Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

need help: insert item into listbox in thread #587

Open
zl03jsj opened this issue Jul 28, 2023 · 6 comments
Open

need help: insert item into listbox in thread #587

zl03jsj opened this issue Jul 28, 2023 · 6 comments
Labels

Comments

@zl03jsj
Copy link

zl03jsj commented Jul 28, 2023

Description:

I have a thread purpose to read some data, then insert the item with the data into a listbox,
but the listbox doesn't refresh automatically,
unless i press some key on the listbox. following is my code:

import threading
import time

import urwid


class OrderListBox(urwid.ListBox):
    def __init__(self, max_item_size=20):
        super(OrderListBox, self).__init__(urwid.SimpleListWalker([
            urwid.AttrMap(urwid.Text(
                '{} order content...'.format(0)), None, 'I say')
        ]))
        self.max_item_size = max_item_size
        self.idx: int = 1

    def insert(self):
        text = urwid.Text('{} order content...'.format(self.idx))
        wrap = urwid.AttrMap(text, None, 'I say')
        self.body.insert(0, wrap)
        self.idx = self.idx + 1
        if len(self.body) > self.max_item_size:
            self.body = self.body[:self.max_item_size]

    def keypress(self, size, key):
        key = super(OrderListBox, self).keypress(size, key)
        pass


list_box = OrderListBox()

palette = [('I say', 'default,bold', 'default'), ]
mainloop = urwid.MainLoop(list_box, palette)


def loop_insert():
    while True:
        list_box.insert()
        # mainloop.draw_screen()
        time.sleep(3)


loop_refresh_thread = threading.Thread(target=loop_insert, args=())
loop_refresh_thread.start()

mainloop.run()

mainloop.draw_screen() looks could force the whole screen to refresh,
but i don't known if it is the correct way, maybe there are some better approach to do this?

@zl03jsj zl03jsj changed the title need help: insert item into listbox in another thread need help: insert item into listbox in thread Jul 28, 2023
@danschwarz
Copy link
Contributor

What version of Urwid are you running? This sounds a lot like the problem I'm experiencing with #575 , running against the latest master.

@penguinolog
Copy link
Collaborator

What version of Urwid are you running? This sounds a lot like the problem I'm experiencing with #575 , running against the latest master.

No, threading works correctly. Asyncio based code has issues

@penguinolog
Copy link
Collaborator

penguinolog commented Aug 21, 2023

Correct way: _invalidate() modifies widget:

class OrderListBox(urwid.ListBox):
    def __init__(self, max_item_size=20):
        super().__init__(urwid.SimpleListWalker([
            urwid.AttrMap(urwid.Text(
                '{} order content...'.format(0)), None, 'I say')
        ]))
        self.max_item_size = max_item_size
        self.idx: int = 1

    def insert(self):
        text = urwid.Text('{} order content...'.format(self.idx))
        wrap = urwid.AttrMap(text, None, 'I say')
        self.body.insert(0, wrap)
        self.idx = self.idx + 1
        if len(self.body) > self.max_item_size:
            self.body = self.body[:self.max_item_size]
        self._invalidate()
        # this is the bottom-most widget, which was modified. All top-level widgets will be handled automatically

    def keypress(self, size, key):
        key = super().keypress(size, key)

@penguinolog
Copy link
Collaborator

Also you can connect callback to the SimpleListWalker instance, if you are not making some extra modifications after insert of items

@zl03jsj
Copy link
Author

zl03jsj commented Sep 3, 2023

Correct way: _invalidate() modifies widget:

class OrderListBox(urwid.ListBox):
    def __init__(self, max_item_size=20):
        super().__init__(urwid.SimpleListWalker([
            urwid.AttrMap(urwid.Text(
                '{} order content...'.format(0)), None, 'I say')
        ]))
        self.max_item_size = max_item_size
        self.idx: int = 1

    def insert(self):
        text = urwid.Text('{} order content...'.format(self.idx))
        wrap = urwid.AttrMap(text, None, 'I say')
        self.body.insert(0, wrap)
        self.idx = self.idx + 1
        if len(self.body) > self.max_item_size:
            self.body = self.body[:self.max_item_size]
        self._invalidate()
        # this is the bottom-most widget, which was modified. All top-level widgets will be handled automatically

    def keypress(self, size, key):
        key = super().keypress(size, key)

thanks for your reply, it help me a lot.

@zl03jsj
Copy link
Author

zl03jsj commented Sep 3, 2023

As @penguinolog has left the correct approach, i will close this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants