I am using Qt Designer to manage a large UI and Pyside for the code. I'm looking to display a ComboBox in my Table.
The following answer gives a pretty detailed description of how to accomplish this when managing the UI yourself:
PyQt - How to set QComboBox in a table view using QItemDelegate
My question is: How would this work when the UI is already created for me by pyside-uic? The code in the link includes, more or less:
class TableView(QtGui.QTableView):
def __init__(self, *args, **kwargs):
QtGui.QTableView.__init__(self, *args, **kwargs)
# Set the delegate for column 0 of our table
self.setItemDelegateForColumn(0, ComboDelegate(self))
[...]
class Widget(QtGui.QWidget):
self._tm=TableModel(self)
self._tv=TableView(self)
self._tv.setModel(self._tm)
Does this mean that if I have a UI file, I still need to write out, then call something like the TableView object myself? Should I create a TableView in Qt Designer, then overwrite it with one I've created that inherits from QTableView and adds setItemDelegate?
Thanks in advance!
The subclass in the example is redundant, because it doesn't re-implement or add any methods. It could be re-written like this:
from PySide import QtGui, QtCore
from mainwindowui import Ui_MainWindow
class MainWindow(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.setupUi(self)
self._model = TableModel(self)
self._delegate = ComboDelegate(self)
self.tableView.setModel(self._model)
self.tableView.setItemDelegateForColumn(0, self._delegate)
Thus, the table-view is accessed as an attribute of the object that is passed to the setupUi method of the UI class generated by pyside-uic.
But what if you did need to subclass one of the classes from Qt Designer? The way to do that is to promote it to a custom class that will replace it when the python UI module is imported.
If you right-click a widget in Qt Designer and select "Promote to...", it will bring up a dialog. In the dialog, you can set a custom class name (say, "TableView"), and also set the header file to the python module it should be imported from (say, "mypkg.mainwindow"). If you then click "Promote", Qt Designer will show the classname as TableView rather than QTableView.
After re-generating the UI module, you'll then see an extra import line at the bottom of the file that looks like this:
from mypkg.mainwindow import TableView
So the custom TableView class will be used instead of a QTableView, and get all the settings from Qt Designer - plus whatever re-implemented stuff you want to add yourself.
Related
If I've created a QMainWindow instance, and assign the central widget and dock widgets for it:
class MyWindow(QtGui.QMainWindow):
def __init__(self, MyCentralWidget, MyDockWidget):
super(MyWindow,self).__init__()
self.setCentralWidget(MyCentralWidget)
self.addDockWidget(Qt.LeftDockWidgetArea,MyDockWidget)
self.show()
Instance=MyWindow(A,B)
Then I think I can get access to the center widget A by Instance.centralWidget(), but how can I get access to the dockwidget in the LeftDockWidgetArea similarly? (for example, I want to modify the properties of the Widget in that dockwidget after instance is created)
try:
self.dockWidgetContents.your_widget...
I used Qt Designer to create a .ui file then pyside-uic to convert to a .py file (ui_mainWindow.py with class Ui_MainWindow). I'm heeding the warning not to edit the .ui or .py because any changes there will be overwritten when saving updates in Qt Designer. So I have my own separate code that should be inheriting from it using the python's super functionality.
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setupUi(self)
self.assignWidgets()
self.show()
I'm able to update labels and respond to buttons and such but I'm not able to use the localization translation stuff. Part of the above class is this function:
def connecetSerialPushed(self):
self.label_connected.setText(self.QtGui.QApplication.translate(self, "Connected: Yes", None, self.QtGui.QApplication.UnicodeUTF8))
If I just do a pure setText and the "Connected: Yes" string, I get no error. But doing that translation results in an error: AttributeError: 'MainWindow' object has no attribute 'QtGui'. I don't get it.. I thought I inherited everything from Ui_MainWindow including it's import of QtGui. What am I missing?
Inside my separate code, I did
from PySide import QtGui
and then changed the translation line to
self.label_connected.setText(QtGui.QApplication.translate("MainWindow", "Connected: Yes", None, QtGui.QApplication.UnicodeUTF8))
Thanks ray for clearing up my confusion.
I want to improve my code but currently have not much idea how.
So I used Qt Designer and created a main window plus 3 dialogs which can be opened from main window. Converted .ui files to .py files and created the MainWindow class which manages all.
Everything works fine, but for me this looks wrong:
class MainWindow(QMainWindow, Ui_MainWindow):
# init and else
[...]
def open_add_dialog(self):
self.dialog = AddDialog()
self.dialog.show()
def open_edit_dialog(self):
self.dialog = EditDialog()
self.dialog.show()
def open_about_dialog(self):
self.dialog = AboutDialog()
self.dialog.show()
def assign_widgets(self):
self.actionAdd.triggered.connect(self.open_add_dialog)
self.actionEdit.triggered.connect(self.open_edit_dialog)
self.actionAbout.triggered.connect(self.open_about_dialog)
Code is simplified.. So as you see I've 3 almost equal methods. So the question comes to my mind is it possible to merge all into one? What I want is something like this:
def open_dialog(self):
sender = self.sender()
sender.show()
I think you should never use the sender method of Qt because it makes calling the method from another function impossible, you can then only use it via the signal/slot mechanism. It therefore says in the documentation that: "This function violates the object-oriented principle of modularity". Using it during debugging is fine, of course.
In your case the methods are quite small. You could use lambdas in the connect statement so that you don't have to make separate methods. Or you could create the dialogs in the constructor and only connect to the show methods. Like this:
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self):
self.add_dialog = AddDialog()
self.edit_dialog = EditDialog()
self.about_dialog = AboutDialog()
def assign_widgets(self):
self.actionAdd.triggered.connect(self.add_dialog.show)
self.actionEdit.triggered.connect(self.edit_dialog.show)
self.actionAbout.triggered.connect(self.about_dialog.show)
Im making a QTableWidget in Pyqt and ran into a bit of an annoying hiccup.
I need to use widgets in my table for its functionality, so im using setCellWidget to add them to the table. However, widgets dont have the same methods available as QTableWidgetItem's do (especially regarding selection in the table).
Im wondering if its possible to do something subclassing both items, so i can have the methods of both, and how i woulda dd that to the table.
Something like:
class TableItem(QtGui.QTableWidgetItem, QtGui.QWidget):
def __init__(self, parent=None):
super(TableItem, self).__init__(parent)
self.check = QtGui.QCheckBox()
self.label = QtGui.QLabel('Some Text')
self.h_box = QtGui.QHBoxLayout()
self.h_box.addWidget(self.check)
self.h_box.addWidget(self.label)
and then somehow add that to my table as a TableWidgetItem so it displays widgets and also has selection methods available.
Any ideas here?
For reference:
setCellWidget: http://pyqt.sourceforge.net/Docs/PyQt4/qtablewidget.html#setCellWidget
QWidget: (easy to find, i cant post more than 2 links)
-Which doesnt have the nice methods for a table
QTableWidgetItem: http://pyqt.sourceforge.net/Docs/PyQt4/qtablewidgetitem.html#type
with isSelected and setSelected (Methods not avialble from a widget used in setCellWidget.
To return the widget in a cell you can use table.cellWidget(row, column) and then use your widgets methods on that. But beacuse setSelected and isSelected arent methods of a widget, you cant check for selection. I was hoping to subclass the two together to allow for both
--Basically I need to know how to get my class to 'return' the proper type when i call it to add to the table with setItem
I am not sure what you want to do but you could "inject" a method like:
class TableWidgetItem(QtGui.QTableWidgetItem):
def __init__(self, parent=None):
QtGui.QTableWidgetItem.__init__(self)
def doSomething(self):
print "doing something in TableWidgetItem"
class Widget(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self)
tableWidgetItem = TableWidgetItem()
widget = Widget()
def widgetFunction(self):
tableWidgetItem.doSomething()
# as an instance method
settatr(widget, "widgetFunction", MethodType(widgetFunction, widget, type(widget)))
# or as a class method
settatr(widget, "widgetFunction", widgetFunction)
Then you can:
>>>widget.widgetFunction()
doing something in TableWidgetItem
(not tested)
The code below creates a simple QComboBox. But instead of using a "traditional" .addItem('myItemName') method it creates QStandardItem first and then adds it via QComboBox's .model().appendRow(). Since now I can access each QStandardItem individually I wonder if there is a way to assign CSS to each of them (to each QStandardItem) individually. The goal is to customize each item displayed in ComboBox pulldown menu. So far I am only able to assign a single CSS style to entire ComboBox globally.
from PyQt4 import QtCore, QtGui
app = QtGui.QApplication([])
class Combo(QtGui.QComboBox):
def __init__(self, *args, **kwargs):
super(Combo, self).__init__()
for each in ['Item_1','Item_2','Item_3','Item_4','Item_5']:
item=QtGui.QStandardItem(each)
self.model().appendRow(item)
tree=Combo()
sys.exit(app.exec_())
It looks like this class has no setStyleSheet method, but you can use setBackground, setForeground and setTextAlignment methods. With QBrush you be able to customize elements. Of course it isn't so powerful as styleSheets but better than nothing.
http://pyqt.sourceforge.net/Docs/PyQt4/qstandarditem.html