PyQt5 - Getting information from a QcomboBox on TableWidget - python

I'm looking for some piece of code that enables me to get the information of a combobox that I've put it on a TableView created by QtDesigner.
For lack of knowledge I'm not using any classes or Delegates. When I was using TableWidget the line TableWidget.cellWidget(indexofthecurrentrow, 4).currentIndex() == 0 returned me the current status of the row allowing me to update the database, but that line doesn't work on TableView I'm assuming because of the model or absence of a Delegate.
Relevant Code Below:
for row in range(len(data_from_sqlite)):
comboBox = QComboBox()
comboBox.addItems('opt1', 'opt2')
index_combo = tableview.model().index(row, 5)
tableview.setIndexWidget(index_combo, comboBox)
I just don't know how to retrieve this QComboBox state through other function connected in a button.
I've tried both
tableview.model().index(0,4).itemData().currentIndex() #crashes
and
tableview.model().index(0,4).data() #returns None
Thanks in advance for any help.

I found a solution to a my problem and as pointed by musicamante the solution involves using classes witch is very basic and was very difficult for me.
The loop that implements the combobox in the tableview is:
for row in range(len(data)):
combo = combomaker(self)
index_combo = self.tableview.model().index(row, 5)
self.tableview.setIndexWidget(index_combo, combo)
being the combo maker as it follows
class combo(QComboBox):
def __init__(self, parent):
super().__init__(parent)
self.addItems(['a', 'b'])
self.currentIndexChanged.connect(self.getComboValue)
def getComboValue(self):
print(self.currentText())
# return self.currentText()
I took the code from Jie Jenn https://www.youtube.com/watch?v=KMJTJNUzo4E
Hope this help some clueless programmer in the future.

Using cell widgets makes absolutely no interaction with the table's model and its data.
If you need to access a specific cell widget, use the getter function opposite to setIndexWidget(), indexWidget():
combo = tableview.indexWidget(tableview.model().index(0,4))
combo_index = combo.currentIndex()

Related

QTableWidget Signal and Slot move fields

I wonder if someone knows this.
as in attached pic let's say I have a tabwidget in qt designer and some lineEdit fields. What
I want to achieve is, if the user clicks on a row of the tabwidgets the values of the items will be moved to the lineEdit fields. I saw I can somehow connect them but how to achieve this with the signal and slot functionality in qt designer without programming.
No, it is not possible without implementing code manually as there is no signal to send the text. The logic is:
self.tableWidget.cellDoubleClicked.connect(self.handle_cellDoubleClicked)
# or self.tableWidget.cellClicked.connect(self.handle_cellDoubleClicked)
def cellDoubleClicked(self, row, column):
item = self.tableWidget.item(row, column)
text = item.text() if item is not None else ""
self.lineEdit.setText(text)

How does one update a field from outside the __init__() function with pyqt5

I am reading a sensor and want to display its output as a decimal number in a GUI using PyQt5. I have found a number of tutorials that point out the label.setText('myStr') function. This does not work for my setup, however, because I need to update the field based on the input from another function. I'm not very familiar with PyQt5 yet, and I would appreciate any insight into how this problem ought to be approached.
Note: (I am using LCM to acquire data from a Raspberry Pi. I'm not sure that that is relevant to the problem, but it helps explain my code below.)
Here is what I am trying to do:
class Home_Win(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
loadUi("sensor_interface.ui", self)
self.label_temp.setText('temperature') #Just to verify that I can change it from here
def acquire_sensors(self):
temp = 0 #Make variable available outside nested function
def listen(channel, data):
msg=sensor_data.decode(data)
temp = msg.temperature
lc = lcm.LCM()
subscription = lc.subscribe("sensor_data_0", listen)
while True:
lc.handle()
self.label_temp.setText(str(temp))
Any thoughts on how I can update the GUI to display the readings I am getting from my sensors?
Thanks!
You're almost there. All you need to do is to save the ui in an instance variable in __init__:
self.ui = loadUi("sensor_interface.ui", self)
Then, assuming label_temp is the name of your QLabel widget, just do:
self.ui.label_temp.setText(str(temp))
It turned out that I needed to add repaint(). I also switched to a QLineEdit as this seemed to work better for me. So inside the while loop I now have:
self.ui.lineEdit_temp.setText(str(temp))
self.ui.lineEdit_temp.repaint()
This now outputs live updates to the GUI while reading the data stream.

How to hide QComboBox items instead of clearing them out

I can't find a way to hide QComboBox items. So far the only way to filter its items out is to delete the existing ones (with .clear() method). And then to rebuild the entire QComboBox again using its .addItem() method.
I would rather temporary hide the items. And when they are needed to unhide them back.
Is hide/unhide on QCombobox items could be accomplished?
In case someone still looking for an answer:
By default, QComboBox uses QListView to display the popup list and QListView has the setRowHidden() method:
qobject_cast<QListView *>(comboBox->view())->setRowHidden(0, true);
Edit: fix code according to #Tobias Leupold's comment.
Edit: Python version:
# hide row
view = comboBox.view()
view.setRowHidden(row, True)
# disable item
model = comboBox.model()
item = model.item(row)
item.setFlags(item.flags() & ~Qt.ItemIsEnabled)
# enable item
view.setRowHidden(row, false)
item.setFlags(item.flags() | Qt.ItemIsEnabled)
To build on what #kef answered:
(excuse the C++ on the python question)
By default the QComboBox will use a QListView for the view, thus you can do the following:
QListView* view = qobject_cast<QListView *>(combo->view());
Q_ASSERT(view != nullptr);
view->setRowHidden(row, true);
The one drawback with the above is, that even though the item will be hidden from the popup, the user can still select it using the mouse wheel. To overcome this add the following for the hidden row:
QStandardItemModel* model = qobject_cast<QStandardItemModel*>(combo->model());
Q_ASSERT(model != nullptr);
QStandardItem* item = model->item(row);
item->setFlags(item->flags() & ~Qt::ItemIsEnabled);
With the above the row will be hidden and the user will not be able to scroll to it with the mouse wheel.
To unhide it, just do the reverse:
view->setRowHidden(row, false);
item->setFlags(item->flags() | Qt::ItemIsEnabled);
You can use the removeItem() method to remove an item from the QComboBox.
void QComboBox::removeItem ( int index )
Removes the item at the given index from the combobox. This will update the current index if the index is removed.
This function does nothing if index is out of range.
If you don't know the index, use the findText() method.
There are no hide/unhide methods for QComboBox items.
Althought there is no direct way to hide the item of the QComboBox, but you can use QComboBox::setItemData and set the size to (0,0) to hide the item of QComboBox:
comboBox->setItemData(row, QSize(0,0), Qt::SizeHintRole);
Use the setVisible() to alter the visibility of your object:
.setVisible(False) # Not Visible
.setVisible(True) # Visible
To show the item again:
comboBox->setItemData(row, QVariant(), Qt::SizeHintRole);
Note: changing the SizeHintRole doesn't work on OS X.
I came across this thread after getting frustrated with a lack of hide functionality that would keep the item indexing etc.
I got it to work based on #Kef and #CJCombrink answers. This is basically just a python translation.
I had a problem with qobject_cast.
Solved it by setting .setView(QListView()) to the QComboBox.
combo=QComboBox()
combo.setView(QListView())
hide:
combo.view().setRowHidden(rowindex,True)
tmp_item=combo.model().item(rowindex)
tmp_item.setFlags(tmp_item.flags() & ~Qt.ItemIsEnabled)
unhide:
combo.view().setRowHidden(rowindex,False)
tmp_item=combo.model().item(rowindex)
tmp_item.setFlags(tmp_item.flags() | Qt.ItemIsEnabled)
I decided to subclass the QComboBox and add the hide functionality. Bellow is an use example for testing.
You are welcome to use it. I make no assurances.
import sys
from PySide2.QtWidgets import *
from PySide2.QtCore import *
from PySide2.QtGui import *
#subclassed QComboBox with added hide row functionality
class ComboBox_whide(QComboBox):
def __init__(self):
super().__init__()
self.setView(QListView())#default self.view() is a QAbstractItemView object which is missing setRowHidden, therefore a QListView needs to be set
def hide_row_set(self,row,value=True):
"""sets the row accesibility
value=True hides the row"""
self.view().setRowHidden(row,value)#hides the item from dropdown, however the item is stil accesible by moving down with arrow keys or mouse wheel. The following disables solves that
tmp_item=self.model().item(row)
if value:#hide -> disable
tmp_item.setFlags(tmp_item.flags() & ~Qt.ItemIsEnabled)
else:#enable
tmp_item.setFlags(tmp_item.flags() | Qt.ItemIsEnabled)
def hide_row_toggle(self,row):
"""toggles the row accesibility"""
if self.view().isRowHidden(row):#is hidden, therefore make available
self.hide_row_set(row,False)
else:#is not hidden, therefore hide
self.hide_row_set(row,True)
class Main(QMainWindow):
def __init__(self):
super().__init__()
cwidg=QWidget()
clayer=QVBoxLayout()
cwidg.setLayout(clayer)
self.setCentralWidget(cwidg)
#button for testing
self.btn=QPushButton('Button')
self.btn.setCheckable(True)
clayer.addWidget(self.btn)
#subclassed QComboBox
self.combo=ComboBox_whide()
for n in range(3):#add 3 items with tooltips
self.combo.addItem('item%i'%n)
self.combo.setItemData(n,'tip%i'%n,Qt.ToolTipRole)
clayer.addWidget(self.combo)
#button test function - choose either or for testing
self.btn.clicked.connect(self.btn_clicked)
#uncomment for add/remove example self.btn.clicked.connect(self.remove_add_item)
def btn_clicked(self):
self.combo.hide_row_toggle(1)
def remove_add_item(self):# here for naive comparison and to show why removing and adding is not ok
if self.combo.count()==3:
self.combo.removeItem(1)
else:
self.combo.addItem('new')#new "item1" withouth the ToolTip
if __name__ == '__main__':
app = QApplication.instance()
if app is None:#Pyside2 ipython notebook check
app = QApplication(sys.argv)
main = Main()
main.show()
app.exec_()

PyQt4 Getting the name of QTableWidget that user last clicked from multiple QTableWidgets

I have 10 QTablewidgets. Each of the QTableWidget display different data. I want to get the name of the table widget that the last time user clicked ( on any of the cells).
Currently i tried putting all the tables in a list:
table1 = QtGui.QTableWidget()
table2 = QtGui.QTableWidget()
...
...
mytablelist = [table1,table2,....]
Using Signal and Slots I tried this:
for item in mytablelist:
self.connect(item,QtCore.SIGNAL("cellClicked()"),self.Identify)
My Identify function is as below:
def Identify(self):
sender = self.sender()
print sender
As far as i understand, the sender() method should tell me which Qobject the signal is coming from.
I don't seems to get any output from Identify function. What is causing the problem and how do i fix it?
Is there any better approach to this problem?
I think i found the problem. It was the problem with the signal cellClicked() i used (i have no idea why).
So, I tried to use itemSelectionChanged() signal instead of cellClicked() i used in my question. It works fine now. After that i just used index() method to get the position of table in the tablelist.
tableindex = mytablelist.index(sender)

How to get (childless) “tabs” in a pygtk application

I am facing the problem to need tabs in a pygtk app. Pretty much just like gedit has, but without any per-child widget content.
I’ve come across gtk.Notebook, but that requires me to put a widget for each tab, which I don't want.
The reason is, that I have one widget, but would only like to updates its content based on which tab is selected.
Any hints on how to do that?
My idea so far would be to just add some invisible widget for each tab and then connect to the select-page signal. Which widget could I use as invisible widget, or is there a better/alternative way of achieving my goal?
The invisble widget idea works. But not with gtk.Invisible (this just crashes), but with gtk.HBox() or any other thing that seems empty.
self.notebook.append_page(gtk.HBox(), gtk.Label("title"))
Now if I want to display stuff inside the tab actually, I can use reparent to move the widget to the current tab like this.
class Tab(gtk.HBox):
def __init__(self, child):
self.child = child
self.notebook.append_page(Tab(myWidget), gtk.Label("title"))
def pageSelected(self, notebook, page, pagenum):
box = notebook.get_nth_page(pagenum)
box.child.reparent(box)
You can have global widgets, one per tab as you want, in order to access them easily when the tab is selected.
self.notebook.append_page(self.rightBox, gtk.Label("Orders"))
Then connect to the "switch page" signal
self.notebook.connect("switch-page", self.pageSelected)
and :
def pageSelected(self, notebook, page, pagenum):
name = notebook.get_tab_label(notebook.get_nth_page(pagenum))
Now you have "name" with the label of the currently selected page. Just test it (if name == "Orders" ...) to interact.
Hope this was of some help !

Categories