combo box using different display text and return value [duplicate] - combobox

This question already has an answer here:
Trying to take a value from a dictionary of a ComboBox and instert the key in a textEdit
(1 answer)
Closed 2 years ago.
I have a drop down which the displayed text is populated from a csv:
fish_events_terms = gpd.read_file("domains/FISH/events/thesaurus_terms.csv")
self.comboActivityType.addItems(list(map(lambda x: x.upper(), fish_events_terms['TERM'])))
I want to display the above but record the uid of that value in this case CLA_GR_UID
So the user sees some text from the TERM column and the value of CLA_GR_UID is passed.

I'm not sure if I understand the question correctly, but if you want to store extra data in an item in addition to the displayed text, you could add the items on-by-one by using QComboBox.addItem(text, user_data), i.e.
from PyQt5 import QtWidgets, QtCore
import pandas as pd
class Widget(QtWidgets.QWidget):
def __init__(self, parent = None):
super().__init__(parent)
self.combo = QtWidgets.QComboBox(self)
# some data
self.df = pd.DataFrame({'TERM': ['apple', 'banana', 'cherry', 'date', 'grape'],
'UID': [1, 2, 3, 4, 5]})
# for each row in dataframe, add item with value in 'TERM' column as text and value in 'UID' column as data
for row in self.df.itertuples():
self.combo.addItem(row.TERM, row.UID)
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.combo)
self.combo.currentIndexChanged.connect(self.combo_index_changed)
def combo_index_changed(self, index):
# retrieve user data of an item in combo box via QComboBox.itemData()
print(f'index {index}, text {self.combo.itemText(index)}, uid {self.combo.itemData(index)}')
if __name__ == "__main__":
app = QtWidgets.QApplication([])
w = Widget()
w.show()
app.exec()

Related

Is there a way to use/get the value from a current entry window

I'm trying to get the variable that's entered in an entry widget on the Return key pressed event, but struggling a bit. What I have tried has always produced a blank result.
This code may look messy and hap-hazard, but it's only going to be a template that I'll be using on a current project!
I've tried that many things to get it to work, I can't remember what I have tried!
from collections import OrderedDict
try:
import tkinter as tk
except:
import Tkinter as tk
root = tk.Tk()
labelLIST = OrderedDict([
('Temp ID', 'tempID'),
('PO Number', "poNumber"),
('Reference', "reference"),
('Cut/Sample Date', "csDate"),
('Cut Number', "cut")
])
i = 0
e_loops = len(labelLIST)
print (e_loops)
def bval1(event=None):
for i in range(e_loops):
print (entries[i].get())
entries[0].delete(0, tk.END)
entries[0].insert(0, 'DISABLED')
entries[0].configure(state='disabled')
def bval2():
entries[0].configure(state='normal')
for i in range(e_loops):
entries[i].delete(0, tk.END)
entries[0].focus()
def onClick(event):
ent = event.widget # event.widget is the widget that called the event
print(ent.cget("text")) # Print the text for the selected button
event.widget.tk_focusNext().focus()
def enterEV(event):
# print(entries[].get())
event.widget.tk_focusNext().focus()
entries = []
for key, value in labelLIST.items():
label = tk.Label(root, text=key)
label.grid(row=i, column=0, sticky="ew", padx=1, pady=1)
entry = tk.Entry(root, width=10)
entry.grid(row=i, column=1, sticky="ew", padx=5, pady=5)
if value == "cut":
entry.bind('<Return>', bval1)
else:
# entry.bind('<Return>', enterEV)
entry.bind('<Return>', onClick)
entries.append(entry)
i = i+1
button = tk.Button(root, text="Submit", command=bval1)
button.grid(row=0, column=2, columnspan=9, sticky="ew")
button = tk.Button(root, text="Clear", command=bval2)
button.grid(row=1, column=2, columnspan=9, sticky="ew")
entries[0].focus()
tk.mainloop()
When enter/return is pressed, I want the value that is the entry box to be printed to terminal via the onClick event. But the output is always empty.
def onClick(event):
ent = event.widget # event.widget is the widget that called the event
print(ent.cget("text")) # Print the text for the selected button
event.widget.tk_focusNext().focus()
You don't use the text attribute to get the value in an Entry widget. Using cget("text") returns the value for the textvariable attribute. Since you haven't set that attribute, it will always be the empty string.
Instead, you need to call the get method:
print(ent.get())

How do I add a combobox to first column cells in QtRuby?

I've been trying to add a simple combobox with four items to a stupid table widget cell and I still can't get it placed in the correct row and column. The best I could get was to make it show up only if I tell the combobox its parent is the table widget, the problem is it gets located at position x 0 y 0 of the table widget. I use setCellWidget method and it still doesn't populate the correct cell no matter what row and column I specify there. What should I do then?
I've found this example in PyQt but whenever I try to implement a ruby-esque version of it on Ruby it just doesn't work.
This code does what you were looking for: generate a n×m table, and insert a combobox at a given cell, here at row 4 / column 2.
require 'Qt4'
qt_app = Qt::Application.new(ARGV)
win = Qt::Dialog.new
win.show
table_widget = Qt::TableWidget.new(win)
layout = Qt::GridLayout.new(win) # not required
layout.addWidget(table_widget) # not required
rows = table_widget.rowCount = 7
columns = table_widget.columnCount = 4
(0..rows-1).each do |row|
(0..columns-1).each do |column|
text = "cell #{row}/#{column}"
table_widget.setItem(row,column, Qt::TableWidgetItem.new(text))
end
end
combo_box = Qt::ComboBox.new(table_widget)
combo_box.insertItems(0, ["one", "two", "three", "four", "five"])
table_widget.setCellWidget(4, 2, combo_box)
table_widget.show
qt_app.exec

How to pass input data from a tablewidget to a combo box by clicking pushbutton?

I want to input data in my table and then have it appear in my combo box after pressing 'ok' pushbutton in pyqt. May I know how to go about doing that? Whenever I run my code it just says there is an error at self.comboBox.addItem(item). I don't know which other command to use. Here is part of my code:
def setup(self, Dialog):
...
...
self.comboBox = QtGui.QComboBox(Dialog)
self.comboBox.setGeometry(QtCore.QRect(20, 100, 431, 22))
self.comboBox.setObjectName(_fromUtf8("comboBox"))
self.tableWidget = QtGui.QTableWidget(Dialog)
self.tableWidget.setGeometry(QtCore.QRect(20, 470, 651, 71))
self.tableWidget.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
self.tableWidget.setTextElideMode(QtCore.Qt.ElideRight)
self.tableWidget.setVerticalScrollMode(QtGui.QAbstractItemView.ScrollPerItem)
self.tableWidget.setRowCount(1)
self.tableWidget.setColumnCount(129)
self.tableWidget.setObjectName(_fromUtf8("tableWidget"))
self.tableWidget.horizontalHeader().setVisible(True)
self.tableWidget.horizontalHeader().setDefaultSectionSize(25)
self.tableWidget.horizontalHeader().setMinimumSectionSize(26)
self.tableWidget.verticalHeader().setDefaultSectionSize(25)
self.tableWidget.verticalHeader().setHighlightSections(True)
self.pushButton_7 = QtGui.QPushButton(Dialog)
self.pushButton_7.setGeometry(QtCore.QRect(220, 650, 75, 23))
self.pushButton_7.setObjectName(_fromUtf8("pushButton_7"))
self.pushButton_7.clicked.connect(self.additem)
def retranslateUi(self, Dialog):
...
...
self.tableWidget.setSortingEnabled(False)
def additem(self):
item = self.tableWidget.item(0,0)
self.comboBox.addItem(item)
UPDATE: The solution only works for the first box of my tablewidget. I tried to do it like this:
def additem(self):
while true:
item = self.tableWidget.item(0, 0).text()
self.comboBox.addItem(item)
item1 = self.tableWidget.item(0, 1).text()
self.comboBox.addItem(item1)
However, I just keep getting the error that 'NoneType' object has no attribute 'text'
UPDATE: I tried your suggestion. I tried to upload images so it would be clearer but I need 10 reputation in order to do so. Anyway, I typed this in the tablewidget: 11 22 33 44 each one in one box for four boxes. But only 11 appeared in combobox after pressing 'ok'. It doesn't work even if I typed my value on the other boxes, it only works for the first box. What I need is for them to appear as '11, 22, 33, 44' in my combo box. Would it be possible to do this? As well as for all 128 columns of my tablewidget?
in addItem(self) item is tableWidgetItem type. What you need is QString to add as comboBox item so try to correct this line only:
item = self.tableWidget.item(0,0).text()
here is working example:
# -*- coding: utf-8 -*-
import sys
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import Qt
class Widget(QtGui.QWidget):
def __init__(self):
super(Widget, self).__init__()
self.layout = QtGui.QVBoxLayout(self)
self.comboBox = QtGui.QComboBox(self)
self.comboBox.setGeometry(QtCore.QRect(20, 100, 431, 22))
self.tableWidget = QtGui.QTableWidget(self)
self.tableWidget.setGeometry(QtCore.QRect(20, 470, 651, 71))
self.tableWidget.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
self.tableWidget.setTextElideMode(QtCore.Qt.ElideRight)
self.tableWidget.setVerticalScrollMode(QtGui.QAbstractItemView.ScrollPerItem)
self.tableWidget.setRowCount(1)
self.tableWidget.setColumnCount(3)
self.tableWidget.horizontalHeader().setVisible(True)
self.tableWidget.horizontalHeader().setDefaultSectionSize(25)
self.tableWidget.horizontalHeader().setMinimumSectionSize(26)
self.tableWidget.verticalHeader().setDefaultSectionSize(25)
self.tableWidget.verticalHeader().setHighlightSections(True)
self.tableWidget.setItem(0, 0, QtGui.QTableWidgetItem("first"))
self.tableWidget.setItem(0, 1, QtGui.QTableWidgetItem("second"))
self.tableWidget.setItem(0, 2, QtGui.QTableWidgetItem("third"))
self.tableWidget.resizeColumnsToContents()
self.pushButton_7 = QtGui.QPushButton("Add item 0.0 to combo")
self.pushButton_7.setGeometry(QtCore.QRect(220, 650, 75, 23))
self.pushButton_7.clicked.connect(self.additem)
self.layout.addWidget(self.comboBox)
self.layout.addWidget(self.tableWidget)
self.layout.addWidget(self.pushButton_7)
def additem(self):
item = self.tableWidget.item(0,0)#.text()
self.comboBox.addItem(item)
if __name__ == '__main__':
app = QtGui.QApplication([])
w = Widget()
w.show()
sys.exit(app.exec_())
EDIT
if you want to add all cells from table row to combo box, your additem should look like this:
def additem(self):
for i in range(0, self.tableWidget.columnCount()):
item = self.tableWidget.item(0,i)
if item != None:
text = item.text()
self.comboBox.addItem(text)
Keep in mind that if table cell is empty (item == None) nothing will be added to combo box

How to update a combo box with a list of items

I am trying to update the list of items in one combobox2 depending on the item selected in another - combobox1.
For example, if the user selects a file.mp3 in combobox1 then combobox2 will display a list of audio extension (.aac, .wav, .wma). However, if the user selects a file.flv from combobox1, combobox2 will display a list of video extensions (.mpg, mp4, .avi, .mov).
I initially thought I could accomplish this with if statements. The initial selection works, but there after, if you continue to choose different files, the combobox2 is not updated. I tried using an Event, but it didn't work.
Below if a very stripped-down version of the code so that you can get the gist:
import wx
import os
import sys
import time
from wx.lib.delayedresult import startWorker
class udCombo(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, 'd-Converter', size=(500, 310))
panel = wx.Panel(self, wx.ID_ANY)#Creates a panel over the widget
toolbar = self.CreateToolBar()
toolbar.Realize()
font = wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD)
font2 = wx.Font(7, wx.DECORATIVE, wx.NORMAL, wx.NORMAL)
directory = wx.StaticText(panel, -1, 'Path to media files: c:\\ffmpeg\\bin', (300, 13))
directory.SetFont(font2)
convertfile = wx.StaticText(panel, -1, 'File:', (270, 53))
convertfile.SetFont(font)
convertfile2 = wx.StaticText(panel, -1, 'Format:', (245, 83))
#Select Media
os.chdir("c:\\ffmpeg\\bin")
wrkdir = os.getcwd()
filelist = os.listdir(wrkdir)
self.formats1 = []
for filename in filelist:
(head, filename) = os.path.split(filename)
if filename.endswith(".avi") or filename.endswith(".mp4") or filename.endswith(".flv") or filename.endswith(".mov") or filename.endswith(".mpeg4") or filename.endswith(".mpeg") or filename.endswith(".mpg2") or filename.endswith(".wav") or filename.endswith(".mp3"):
self.formats1.append(filename)
self.format_combo1=wx.ComboBox(panel, size=(140, -1),value='Select Media', choices=self.formats1, style=wx.CB_DROPDOWN, pos=(300,50))
self.Bind(wx.EVT_COMBOBOX, self.fileFormats, self.format_combo1)
self.format_combo2=wx.ComboBox(panel, size=(100, -1),pos=(300,81))
self.Bind(wx.EVT_COMBOBOX, self.fileFormats, self.format_combo2)
def fileFormats(self, e):
myFormats = {'audio': ('.wav', '.wma', '.mp3'), 'video': ('.mpg', '.mp4', '.mpeg')}
bad_file = ['Media not supported']
myFile = self.format_combo1.GetValue()
f_exten = [x for x in myFormats['audio'] or myFormats['video'] if myFile.endswith(x)]
if f_exten[0] in myFormats['audio']:
self.format_combo2.SetItems(myFormats['audio'])
elif f_exten[0] in myFormats['video']:
self.format_combo2.SetItems(myFormats['video'])
else:
self.format_combo2.SetItems(bad_file)
if __name__ == '__main__':
app = wx.PySimpleApp()
frame = udCombo()
frame.SetSizeHints(500,310,500,310)
frame.Show()
app.MainLoop()
Traceback error:
Traceback (most recent call last):
File "C:\Users\GVRSQA004\Desktop\udCombo.py", line 86, in fileFormats
if f_exten[0] in myFormats['audio']:
IndexError: list index out of range
Use a dictionary to hold the two lists. Then when the user clicks something in the first widget, you can call the second combobox's SetItems(myDict[selection]) method or something along those lines. The error message is because you're trying to do something with a CommandEvent that it doesn't support. They don't have an "rfind" attribute, for example.
EDIT: The new code the OP posted doesn't work because it's only running the list comprehension against the first half of the OR statement. It never runs against the "video" portion, so it returns an empty list if the user chooses anything with a video format extension. It WILL work if you select an audio selection.
Personally, I would recommend creating a video extension list and an audio list. That would be easier to understand in the future should you need to fix it later.

selected item of comboBox in custom Delegate from QTableView

I use a custom delegate to display a column of comboBoxes in my QTableView.
The values are the same for all the comboBoxes so it's not really the population part that gives me trouble.
I want them to show as the selected item, some value that I can retrieve from a database. I have access to the database from the delegate, but in order to send my request, I need the row of the comboBox.
So I guess my question is : how can you iterate over all the rows of the table and do some action from inside the custom delegate ?
If it can help here is my custom delegate class :
class ComboBoxDelegate(QtGui.QItemDelegate):
def __init__(self, parent, itemslist):
QtGui.QItemDelegate.__init__(self, parent)
self.itemslist = itemslist
self.parent = parent
def paint(self, painter, option, index):
# Get Item Data
value = index.data(QtCore.Qt.DisplayRole).toInt()[0]
# value = self.itemslist[index.data(QtCore.Qt.DisplayRole).toInt()[0]]
# fill style options with item data
style = QtGui.QApplication.style()
opt = QtGui.QStyleOptionComboBox()
opt.currentText = str(self.itemslist[value])
opt.rect = option.rect
# draw item data as ComboBox
style.drawComplexControl(QtGui.QStyle.CC_ComboBox, opt, painter)
self.parent.openPersistentEditor(index)
def createEditor(self, parent, option, index):
##get the "check" value of the row
# for row in range(self.parent.model.rowCount(self.parent)):
# print row
self.editor = QtGui.QComboBox(parent)
self.editor.addItems(self.itemslist)
self.editor.setCurrentIndex(0)
self.editor.installEventFilter(self)
self.connect(self.editor, QtCore.SIGNAL("currentIndexChanged(int)"), self.editorChanged)
return self.editor
# def setEditorData(self, editor, index):
# value = index.data(QtCore.Qt.DisplayRole).toInt()[0]
# editor.setCurrentIndex(value)
def setEditorData(self, editor, index):
text = self.itemslist[index.data(QtCore.Qt.DisplayRole).toInt()[0]]
pos = self.editor.findText(text)
if pos == -1:
pos = 0
self.editor.setCurrentIndex(pos)
def setModelData(self,editor,model,index):
value = self.editor.currentIndex()
model.setData(index, QtCore.QVariant(value))
def updateEditorGeometry(self, editor, option, index):
self.editor.setGeometry(option.rect)
def editorChanged(self, index):
check = self.editor.itemText(index)
id_seq = self.parent.selectedIndexes[0][0]
update.updateCheckSeq(self.parent.db, id_seq, check)
And I call it fromthe QTableView like this :
self.setEditTriggers(QtGui.QAbstractItemView.CurrentChanged)
self.viewport().installEventFilter(self)
self.setItemDelegateForColumn(13,ComboBoxDelegate(self, self.checkValues))
Hope I was clear enough, thanks for your attention
Not sure if accessing the database from the delegate is a right thing to do. Your delegate can contain reference to the instance of QAbstractTableModel which the QTableView refers to. You can then use methods in the model to iterate over rows of the table.

Resources