Multiple ListBox columns in urwid - python

I am trying to build an interface as part of a console application that reads an output file and displays part of its contents in a window (split vertically) as a scrollable list. The user should be able to choose items from this list, which when selected show up in the adjacent window. Switching to this adjacent window and selecting items should then remove them. When the user hits 'Q' or some other appropriate keypress, the interface should exit and the choices are then available to the main program for further processing.
I am trying to build this using urwid. I can get the results to show up in a ListBox widget, but when I try to wrap this and a separate instance of a ListBox widget in a Columns widget, the program throws an error on calling the mainloop. Basically, something like this:
listbox1 = urwid.ListBox(urwid.SimpleListWalker[<lines>])
listbox2 = urwid.ListBox(urwid.SimpleListWalker[])
urwid.MainLoop(urwid.Columns([listbox1, listbox2])).run()
I then get:
AttributeError: 'listbox1' object has no attribute 'rows'
I guess because it is a 'flow' style widget it has no specified number of rows, and since the Columns object would be the top level widget, calls to render fail due to not being able to determine the overall size of the screen? If so, what is the best way to work around this?
EDIT: Can simply wrap the columns object in Frame without calling header or footer and get desired output.

Related

How to have multiple widget buttons perform different actions in Jupyter Notebook?

I am trying to make a series of buttons that take samples from a data set based on some scenario. I have a 3x2 group of buttons, each describing a different scenario. I can't seem to get them to perform their separate actions.
I think I understand how to connect the action of clicking a button to its response. However, I don't understand how to do the same for multiple buttons.
Here's my code that worked to get a single, standalone button to work:
button = widgets.Button(description='Generate message!')
out = widgets.Output()
def on_button_clicked(_):
samp_text = raw_data.sample(1).column(1)
# "linking function with output"
with out:
# what happens when we press the button
print(samp_text)
# linking button and function together using a button's method
button.on_click(on_button_clicked)
# displaying button and its output together
widgets.VBox([button,out])
Now what I'm trying to do is take different kinds of samples given various situations. So I have functions written for each type of sampling method that returns a table of proportions:
1 47.739362
2 44.680851
3 4.920213
9 2.659574
Name: vote, dtype: float64
However the same method in the first example with just one button doesn't work the same with multiple. How do I use widgets.Output() and how do I connect it so that clicking the button outputs the corresponding sample summary?
I expect for a clicked button to output its sample summary as shown above.
I didn't have any problem extending your example to use
multiple buttons. I don't know where you were confused.
Sometimes exceptions that occur in widget callbacks do not
get printed -- maybe you had a bug in your code that you couldn't
see for that reason. It's best to have everything
wrapped in a "with out:"
Created two buttons using the list. Guess code itself explains better.
from ipywidgets import Button, HBox
thisandthat = ['ON', 'OFF']
switch = [Button(description=name) for name in thisandthat]
combined = HBox([items for items in switch])
def upon_clicked(btn):
print(f'The circuit is {btn.description}.', end='\x1b\r')
for n in range(len(thisandthat)):
switch[n].style.button_color = 'gray'
btn.style.button_color = 'pink'
for n in range(len(thisandthat)):
switch[n].on_click(upon_clicked)
display(combined)

QToolButton Not Appearing/Overlapping

I am dynamically adding QToolButtons to my toolbar that inherits from QToolBar. I have a list of tuples (widget, callback) that contain what should be added to the toolbar. In theory, I want to group them by the requesting object and separate the groups with addSeparator().
My dictionary of widgets are comprised of three widget tuples, two owned by the same key. Currently, all of my widgets are QToolButtons.
I have tried the following two 'adding' functions with descriptions of results to follow:
# self.registered_widgets is an OrderedDict:
# key: requesting object string, value: ((widget, callback), ...)
def add_registered_widgets_to_toolbar(self):
print "add_registered_widgets_to_toolbar"
#import pdb;pdb.set_trace()
#self.reg... is an OrderedDict
for key in self.registered_widgets.keys():
widgetList = self.registered_widgets[key]
print key
for widgetTuple in widgetList:
print widgetTuple[0]
print widgetTuple[0].parent()
self.addWidget(widgetTuple[0])
self.addSeparator()
This set up results in the first widget never being shown. Ever. I have printed their addresses, parents, and associated keys to confirm that they are as I expect:
three separate widgets
associated with correct key
have my QToolBar class object as parent widget
and are all being processed in the order I expect
All of those conditions are true to no effect.
The second attempt:
def add_registered_widgets_to_toolbar(self):
print "add_registered_widgets_to_toolbar"
#import pdb;pdb.set_trace()
l = self.layout()
for key in self.registered_widgets.keys():
widgetList = self.registered_widgets[key]
print key
for widgetTuple in widgetList:
print widgetTuple[0]
print widgetTuple[0].parent()
l.addWidget(widgetTuple[0]
l.addSeperator()
self.setLayout(l)
This results in all the QToolButton icons overlapping, with the last being the full width of a modal dialog's button. (All of the buttons are created with a set QSize of (24,24).)
Additionally, unlike with the first version of the function, the toolbar never shows properly. Just maybe (I'm guessing) the top four to five pixels are shown between the widget above my toolbar and the widget below. Just enough to make out the tops of my three, very different icons and the width of the last when I hover over it.
I've consulted with those more knowledgeable in the ways of Python than myself and nobody has any ideas, even after running and debugging the program while it runs. I'm at a complete loss.

Updating cell widgets changes in a Qtable without selecting the cell

well I'm using Pyqt4 in Maya2012 to make a reference editor alike ui. I working with a QtableWidget to make the reference list and i have subwidgets in each cell. One of the widgets is a checkbox that unload or reload the reference.
The problem i have is if a click directly in the checkbox without have the cell selected it doesn't do anything
this is my code:
def listConnections(self):
self.pos=self.sender().currentRow()
wid = self.list.ref_l.cellWidget(self.pos, 0).children()
self.text = self.list.list[self.pos]
self.ref()
for wt in wid:
if type(wt)== type(QCheckBox()):
wt.stateChanged.connect(self.changeState)
if type(wt)== type(QComboBox()):
wt.currentIndexChanged.connect(self.changeType)
I'm calling the function with a "itemSlectionChanged" signal because is the only way i knew i could detect the subwidgets.
All the subwidgets are made in the moment i fill the list.
Is there a way to make what i want?
Edit:
This is how i called the function
self.list.ref_l.itemSelectionChanged.connect(self.listConnections)
and this is how i create all the subwidgets in the cells
def fillList(self):
mayaRef = self.findRef()
if len(mayaRef)>0:
for count in range(0,len(mayaRef)):
self.ref_l.insertRow(count)
wid=QWidget()
cLayout=QHBoxLayout()
wid.setLayout(cLayout)
checkWid=QCheckBox()
nameWid=QLabel()
cLayout.addWidget(nameWid)
nameWid2=QLabel()
cLayout.addWidget(nameWid2)
comWid=QComboBox()
cLayout.addWidget(comWid)
self.ref_l.setCellWidget(count,0,wid)
self.ref_l is my QTable Widget, this is in another code that i'm calling with self.list in the original
You should set up all your connections right after you create the check boxes in fillList. Each item is associated with the path of the reference. You can use a QSignalMapper to map each check box to the path, then connect the signal mapper to your changeState slot. The signal mapper then calls that slot with the path you specified.

cursor gone in PyQT

I have a window containing multiple QRowWidgets, which are custom widgets defined by me. These QRowWidgets contain QLineEdits and other standard widgets. To show or hide certain parts of a QRowWidget, I overdefined the focusInEvent() methodes of all the widgets within it. It works perfectly, when I click on the QRowWidget, the hidden elements appear.
The weird thing is that the blinking cursor line hovewer doesn't appear in the QLineEdits within the custom widgets. I can select them both by a mouse click or with Tab, and a glow effect indicates that the QLineEdit is selected in it, I can select a text in it, or start typing at any location wherever I clicked, but the cursor never appears and it's quite annoying.
My 1st thought was that it is a bug on Mac, but I have the same experience on SuSe Linux.
I'm using python 2.7 and PyQt4.
This is in the __init__() of the QRowWidget:
for i in self.findChildren(QWidget):
i.focusInEvent = self.focusInEvent
And then this is the own focusInEvent():
def focusInEvent(self, event):
if self.pself.focusedLine:
self.pself.focusedLine.setStyleSheet("color: #666;")
self.pself.focusedLine.desc.hide()
self.pself.focusedLine.closebutton.hide()
self.setStyleSheet("color: #000;")
self.desc.show()
self.closebutton.show()
self.pself.focusedLine = self
I suspect you do not make a call to the original focusInEvent() when you override it. Your function should look something like:
def focusInEvent(self,...):
QParent.focusInEvent(self,...)
# the rest of your code
where QParent is the nearest base class for your widgets is.
Either that, or make sure you call focusInEvent() on your QLineEdit widgets as part of your function.
Given the comments, it sounds like you are dynamically reassigning the focusInEvent function on the insantiatations in your custom widget. I would either make a derived class for each of the widgets you use that just overrides focusInEvent as above, or include a line like
type(self).focusInEvent(self,..)
in you function.

How to add event listener to dynamic QTableWidgetItem in PyQt4?

I am a Python and Qt newbie...
I am working on a GUI program that shows a list of data using QTableWidget at the beginning.
The rows are inserted into the table using the setItem() method. They are QTableWidgetItem objects.
Now I want to allow users to click-select a certain row (the QTableWidgetItem), and my program will populate a secondary QTableWidget.
I have learnt that there is a thing called Signal and Slot. Am I going to use that?
There are also examples of using installEventFilter(), but it is not appropiate for the QTableWidgetItem.
The easiest way for this would just be to use the itemClicked-signal of the QTableWidget:
def handle_item_clicked(tableItem):
#the callback, called when an item is clicked, with the item as an argument
#populate the secondary table in some way
#register the callback with the QTableWidget
yourTableWidget.itemClicked.connect(handle_item_clicked)
You could also use the currentItemChanged signal which gives you the current and previous selection (e.g. so you can clear or hide your secondary widget if the user deselects an item, in which case the current item will be None).
Qt doesn't have "event listeners". As you mentioned, you do such things by connecting signals to slots.
For example:
QObject.connect(myTableWidget, QtCore.SIGNAL("clicked()"), self.foobar)
This will cause the method self.foobar() to be called when you click on myTableWidget. The foobar function could retrieve which item is selected and populate the second widget based on that.
Take note that in the last argument of connect, you don't use the parentheses (foobar()), just the method name!

Categories

Resources