Automatically scroll down Listbox in Tkinter app - python-3.x

Hi guys I'm making this chat app with tkinter and it works perfectly except by the fact that the text I post in my Listbox, don't shows up the way I want. Once the space in the Listbox finishes, I have to manually scroll down to see recent messages. My question is, what can I do to make the Listbox automatically scroll down when it gets fill. This is the part of the code of the Listbox
lista=Listbox(raiz,font=('Arial'))
lista.pack(side=LEFT,padx=10,pady=10,ipadx=200,fill=X,expand=True )
And this is where I posted:
def post(text,n=0):
winsound.Beep(400,150)
if n==0:
lista.insert(END,text)
campo.delete(0,1000)
else:
for i in text:
lista.insert(END,i)
If you can help me it will be great. Thanks!!!

You need add this line lista.see(tkinter.END) before lista.insert(END,text)

You should clear the Listbox widget before you display the current or insert
def post(text,n=0):
winsound.Beep(400,150)
if n==0:
lista.delete(0, END) # this to clear the listbox and display the current content in the listbox
lista.insert(END,text)
campo.delete(0,1000)
else:
for i in text:
lista.insert(END,i)
Or you can place the new content at top of Listbox like this,
def post(text,n=0):
winsound.Beep(400,150)
if n==0:
return
lista.insert(n-1, text)
campo.delete(0,1000)
else:
for i in text:
lista.insert(END,i)
Since you didn't post your full code or minimal am assuming this how it is.

Related

How to enable/disable button when QComboxBox and QLineEdit are activated

I cannot get a push-button enabled when both a text box is filled and a combox box item is selected.
I have the following code, which enables the button as soon as I enter text, but have no selected combobox item:
self.combo_box.currentIndexChanged[int].connect(self.showbutton)
self.textbox.textChanged.connect(self.showbutton)
def showbutton(self,index):
self.enableNewButton.setEnabled((index != -1) and bool(self.textbox.text()))
So I then did a print(index) and I do see the proper index being printed when I select a combo box item; but I also see each character printed as well when I enter stuff in the text box.
I have no problems enabling buttons based on multiple text input boxes but this one is not working for me.
The textChanged signal sends the current text, which cannot ever be equal to -1. So rather than using the parameters emitted by the signals, you should directly check both values via the widgets themselves, like so:
class Window(QtWidgets.QWidget):
...
def showbutton(self):
self.enableNewButton.setEnabled(
self.combo_box.currentIndex() >= 0 and bool(self.textbox.text()))

Dropdown menus in PysimpleGUI

I am looking for a PysimpleGUI way to create dropdown menus.
Currently, I can create ComboBoxes as such:
import PySimpleGui as sg
sg.Combo(list1, size = params)
This creates an Input box and a dropdown list with a slider populated by list1 elements.
However, my users are very sloppy with inputs and I'd like to restrict them to a simple dropdown list.
Now I know I could maybe use the ListBox element but it doesn't have a slider/seems much less versatile than Combo.
What other arguments could I pass to Combo to make this work?
NB:In the documentation they state that Combo == InputCombo == Drop == DropDown but without giving more details but it confuses me a lot.
There is no slider when ListBox is has not enough entries however one appears when enough are added.
sg.Listbox(list(df_names.NAMES), size=(20,4), enable_events=False, key='_LIST_')
Set the readonly to True
sg.Combo(..., readonly=True)

Python, tkinter and the scrollbar in a grid

This is me trying to get a ListBox with a Scrollbar. I've read about 20 other answers on this site and none seem to work in my situation, so I have to ask my own.
I have a LabelFrame widget in which I have a few labels and a ListBox widget. I want the ListBox widget to have a scrollbar. I cannot seem to get it to work.
Here is the offending code:
self.lbDates = tk.Listbox(master=group, width=12)
self.lbDates.grid(row=3, column=1, padx=3, pady=3)
self.scrollDates = tk.Scrollbar(self.lbDates, orient="vertical")
self.scrollDates.config(command=self.lbDates.yview)
self.scrollDates.grid(row=3, column=1)
self.lbDates.config(yscrollcommand=self.scrollDates.set)
A few questions: is the scrollbar supposed to be in the same space (i.e. the same grid row and column) as the ListBox widget? I supposed it should be, but given how much trouble I've had with this, I feel I should ask.
I should say that the list box is populated by pressing a button elsewhere. Without the scrollbar in place, this date is populated correctly so I'm assuming the problem isn't there.
What happens when I run this code? Well I don't see a ListBox, but I to see the scroll bar. Now when there's supposed to be data in there (and I know because I populate it), I see what you might imagine is the correct scrollbar, although the ListBox is either invisible or hidden or something. It flickers on for a fraction of a second when it's populated but then is hidden again.
I can show you, in fact, an example of this.
The top one has no data in and the second has data in. Of course you can't see the data, but you can see that it's supposed to be there. And if I remove the scrollbar, I do get the data I expect in the ListBox widgets. I would like to show an image of the moment it populates before it disappears but it seems like a single frame and I can't catch it.
I'm sure my mistake must be something very simple here, and I very much hope someone can assist. I am using tkinter for the widgets and Python 3.7.
Edit: I have made some alterations as suggested below, so that my ListBox and Scrollbar now exist in a Frame and that Frame is within the LabelFrame object. As follows:
fr = tk.Frame(master = group)
fr.grid(row=4, column=1)
self.lbDates = tk.Listbox(master=fr, width=12)
self.lbDates.pack()
self.scrollDates = tk.Scrollbar(master=self.lbDates, orient="vertical")
self.scrollDates.config(command=self.lbDates.yview)
self.scrollDates.pack()
self.lbDates.config(yscrollcommand=self.scrollDates.set)
Unfortunately there is no difference and I seem to be experiencing the exact same problems as before.
is the scrollbar supposed to be in the same space (i.e. the same grid row and column) as the ListBox widget?
It's up to you. Typically you do not put the scrollbar inside the listbox, as it would obscure some of the data in the listbox. The listbox and scrollbar will have the same parent. If you're using grid, usually the vertical scrollbar belongs in the column immediately to the right of the listbox.
What happens when I run this code? Well I don't see a ListBox, but I to see the scroll bar.
That is because the listbox shrinks to fit its children. The listbox is there, but it's only as wide and tall as the scrollbar. This is another reason why you shouldn't put the scrollbar inside the listbox.
If you want the scrollbar to appear as if it's inside the listbox, the best practice is to create a frame that holds the listbox and scrollbar.
You can make the frame sunken and the listbox flat, and it will give the illusion that the scrollbar is inside the listbox. You can then put that frame anywhere you like in your UI and the scrollbar will always be with the listbox.
Both the listbox and the scrollbar need to be children of the frame for this to work.
Here's a simple example:
import tkinter as tk
root = tk.Tk()
lb_frame = tk.Frame(root, bd=1, relief="sunken")
listbox = tk.Listbox(lb_frame, bd=0, yscrollcommand=lambda *args: vsb.set(*args))
vsb = tk.Scrollbar(lb_frame, orient="vertical", command=listbox.yview)
vsb.pack(side="right", fill="y")
listbox.pack(side="left", fill="both", expand=True)
lb_frame.pack(padx=20, pady=20)
for i in range(1, 100):
listbox.insert("end", f"Item {i}")
root.mainloop()

How to prevent no selection in QTableWidget?

I have a QTableWidget with some rows in it. I want selection to be always present. But once I click somewhere on the Table outside the rows I lose my selection. Could someone help me with this problem?
The simplest solution is to ensure that an item exists at the coordinates the user clicks in.
This can be done by ensuring that QTableWidget.indexAt(pos) returns a valid index: if it is, it means that an item exists there, so we can proceed with the base class mousePressEvent, otherwise we just ignore it.
class AlwaysSelectedTable(QtWidgets.QTableWidget):
def mousePressEvent(self, event):
if self.indexAt(event.pos()).isValid():
QtWidgets.QTableWidget.mousePressEvent(self, event)

Python 3: Is it possible to close an active listbox using code?

I'm learning python (3) and coding a board game as a practice exercise. I want different listboxes to open and close themselves depending on the stage of the game. Thank you for your...input! (heh)
Editing for clarity:
The goal is for the listbox creation function to first check if there are any other open/active listboxes. If there are, to close them.
In effect,I want to guarantee that there is only one listbox open at any given time.
For instance:
def stuff_list():
# creates stuff_list listbox
def another_list():
# code for 'if any other listbox is open, close it'
# creates another_list listbox
So running this:
stuff_list() # opens stuff_list()
another_list() # closes stuff_list and then opens another_list
I don't think there is a need to destroy your current listbox just to create a blank one when you can just erase the one that is there to repopulate it with new info. I suggest you look into the listbox documentation.
To populate a listbox, you use listbox.insert(). To erase it, you use listbox.delete(). Here's some example code:
def populate_listbox():
listbox.insert(END, "a list entry")
for item in ["one", "two", "three", "four"]:
listbox.insert(END, item)
def erase_listbox():
listbox.delete(0, END)

Resources