How can I create a read-only combobox in Pyqt? - python

I have a comboBox with items and I just want to display them without being able to select any of them.I searched in Qt Designer but I can't find the right property. Any ideas ?

You cannot do it in the QtDesigner you have to connect the currentIndexChanged signal with a function that will revert the old value whatever the user selects:
Example:
import sys
from PyQt4 import QtGui, QtCore
class MainWidget(QtGui.QWidget):
def __init__(self):
super(MainWidget, self).__init__()
# Create a combo and set the second item to be selected
self.combo = QtGui.QComboBox()
self.combo.addItems(['foo', 'bar', 'baz'])
self.combo.setCurrentIndex(1)
# Connect the combo currentIndexChanged signal
self.combo.activated.connect(self.on_combo_change)
# Setup layout
self.layout = QtGui.QVBoxLayout()
self.layout.addWidget(self.combo)
self.setLayout(self.layout)
def on_combo_change(self, index):
# Whatever the user do, just ignore it and revert to
# the old value.
self.combo.setCurrentIndex(1)
app = QtGui.QApplication(sys.argv)
mw = MainWidget()
mw.show()
app.exec_()

QComboBox.setEditable(False) should do it: http://pyqt.sourceforge.net/Docs/PyQt4/qcombobox.html#setEditable

Related

QDialog is destroyed before I get data form it

I have QDialog that will extract information from it. I added setAttribute(QtCore.Qt.WA_DeleteOnClose) to make sure to clean up the GUI, but QDialog and its attributes being deleted before extracting them. Error: wrapped C/C++ object of type QLineEdit has been deleted.
How can I maintain QDialog, until I get information I need, then destroy on Accep or reject (like deletelater())?
If the solution is to set setAttribute(QtCore.Qt.WA_DeleteOnClose)==False, How can I effectively delete the QDialog after accept or reject, to make GUI is not increasing in size?
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class Dialog(QtWidgets.QDialog):
def __init__(self, name, parent=None):
super(Dialog, self).__init__(parent)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
#
self.title = QtWidgets.QLabel('name')
self.val = QtWidgets.QLineEdit()
self.val.setText("{} is my infor".format(name))
hbox = QtWidgets.QHBoxLayout()
hbox.addWidget(self.title)
hbox.addWidget(self.val)
#
QBtn = QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel
self.buttonBox = QtWidgets.QDialogButtonBox(QBtn)
self.buttonBox.accepted.connect(self.accept)
self.buttonBox.rejected.connect(self.reject)
#
self.layout = QtWidgets.QVBoxLayout()
self.layout.addLayout(hbox)
self.layout.addWidget(self.buttonBox)
self.setLayout(self.layout)
def main():
app = QtWidgets.QApplication(sys.argv)
ex = Dialog('text')
if ex.exec_() == QtWidgets.QDialog.Accepted:
myinformation = ex.val.text()
print(myinformation)
if __name__ == '__main__':
main()
If you want to get information from the dialog after closing it then you should not use self.setAttribute(QtCore.Qt.WA_DeleteOnClose) since at the moment you want to get the information the dialog will be destroyed.
On the other hand it is not necessary to use deleteLater() since "ex" is a local variable that will be destroyed so there is no memory leak.

How to make one window to block another without using .setModal(True)

If main window right-clicked a QInputDialog shows up. I want QInputDialog to block main window while it is open. How to achieve this?
from PyQt4 import QtCore, QtGui
app = QtGui.QApplication([])
class AppWindow(QtGui.QMainWindow):
def __init__(self):
super(AppWindow, self).__init__()
mainWidget=QtGui.QWidget()
self.setCentralWidget(mainWidget)
mainLayout = QtGui.QVBoxLayout()
mainWidget.setLayout(mainLayout)
frame=QtGui.QFrame()
frame.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
frame.connect(frame, QtCore.SIGNAL("customContextMenuRequested(QPoint)" ), self.up)
mainLayout.addWidget(frame)
self.modal=QtGui.QInputDialog()
def up(self, QPos):
self.modal.move(QtGui.QCursor.pos())
self.modal.show()
self.modal.raise_()
window=AppWindow()
window.show()
sys.exit(app.exec_())
OK, This solution can be solve by use method QWidget.setWindowModality (self, Qt.WindowModality windowModality) . A modal window is one that blocks input to other windows. Note that windows that are children of a modal window are not blocked.
Add this line in your initial method;
self.modal.setWindowModality(QtCore.Qt.ApplicationModal)
Completed code is;
import sys
from PyQt4 import QtCore, QtGui
class AppWindow (QtGui.QMainWindow):
def __init__ (self):
super(AppWindow, self).__init__()
mainWidget = QtGui.QWidget(self)
self.setCentralWidget(mainWidget)
mainLayout = QtGui.QVBoxLayout()
mainWidget.setLayout(mainLayout)
frame = QtGui.QFrame()
frame.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
frame.connect(frame, QtCore.SIGNAL("customContextMenuRequested(QPoint)" ), self.up)
mainLayout.addWidget(frame)
self.modal = QtGui.QInputDialog(self)
self.modal.setWindowModality(QtCore.Qt.ApplicationModal)
def up (self, QPos):
self.modal.move(QtGui.QCursor.pos())
self.modal.show()
self.modal.raise_()
app = QtGui.QApplication([])
window = AppWindow()
window.show()
sys.exit(app.exec_())
Reference method : http://pyqt.sourceforge.net/Docs/PyQt4/qwidget.html#setWindowModality
Reference enum : http://pyqt.sourceforge.net/Docs/PyQt4/qt.html#WindowModality-enum
Regards,
In a nut shell, this is the basic approach. I have created a second window (a Frame), containing a table widget, and the name of my class is TableWindow. Import that in your main window file. On a button click, I call the below function.
def call_table_window(self):
self.frame = QtGui.QFrame()
self.window_table = TableWindow()
self.window_table.setupUi(self.frame)
#This stops the user to switch to the main window. He has to close
#the 2nd window first.
self.frame.setWindowModality(QtCore.Qt.ApplicationModal)
self.frame.show()
Especially when working with PyQt5, you can set inside the __init__
self.setWindowModality(QtCore.Qt.ApplicationModal)

PyQt: Dialog's Minimize Window Button is Missing in OSX

A dialog created with:
class GUI(QtGui.QMainWindow):
def __init__(self):
super(GUI, self).__init__()
global dialog
dialog = QtGui.QDialog()
myGui = GUI()
is missing a minimize window button (OSX). It is there in Windows. Do I have to set some flag to display this missing controller? Please advise, Thanks in advance!
EDITED LATER:
I didn't try to solve a no-minimize-button issue with QtGui.QDialog(). But it appears I partically aware how to get that missing button using QtGui.QMainWindow.
Here is the simplest code illustrating a basic syntax:
from PyQt4 import QtCore, QtGui
app = QtGui.QApplication(sys.argv)
class MainWindow(QtGui.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
myQWidget = QtGui.QWidget()
myBoxLayout = QtGui.QVBoxLayout()
myLineEdit = QtGui.QLineEdit("myLineEdit")
myBoxLayout.addWidget(myLineEdit)
myQWidget.setLayout(myBoxLayout)
self.setCentralWidget(myQWidget)
window = MainWindow()
window.show()
window.resize(480,320)
sys.exit(app.exec_())
A 'key' 'concept' behind QtGui.QMainWindow is that first we declare QWidget()
myQWidget = QtGui.QWidget()
to which we assign a 'main' layout:
myQWidget.setLayout(myBoxLayout)
Last step not to forget is to assign this QWidget() to dialog itself using:
self.setCentralWidget(myQWidget)
where 'self' is an instanced subclass of QtGui.QMainWindow.
I can't test this myself, but you could try setting these window flags:
dialog.setWindowFlags(dialog.windowFlags() |
QtCore.Qt.WindowMinimizeButtonHint |
QtCore.Qt.WindowSystemMenuHint)
(The WindowSystemMenuHint flag may not be necessary).
QtGui.QDialog does not offer a minimize button on any platform, but QtGui.QMainWindow does offer on each platform (Windows, Linux and OSX). You are creating a QDialog object and at the same time an object of GUI which is subclass of QMainWindow. If you write myGui.show() the window will offer you all three buttons (minimize, maximize/restore and close). But in case of dialog.show(), you will not have two of them (minimize and maximize/restore). It's Qt's limitation.

PyQt4 menu acction to add new tab to QTabWidget

I'm working on a small application for work w/ python and PyQt4 for the GUI. What I'm trying to accomplish is having a tabbed GUI where when a user clicks on a menu item, the action taken adds a tab to the QTabWidget. I'm currently having trouble getting an action to do such a thing. I've tried creating the GUI by hand and with QT designer, but I cant figure out how, if at all possible, to get an action to add a tab to the QTabWidget. This is my python code:
import sys
from PyQt4 import QtGui, uic
class TestGUI(QtGui.QMainWindow):
def __init__(self):
super(TestGUI, self).__init__()
uic.loadUi('TEST.ui', self)
self.show()
self.actionAdd_Tab.triggered.connect(addTab)
def addTab():
print 'This works'
#Add new tab to GUI
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = TestGUI()
sys.exit(app.exec_())
Pressing the menu item prints 'This works' to the console, so I know that its calling the addTab() function, but how do I get it to add a Tab?
Let me know if you would like to see the .ui file if it will help
The handler for your action needs to create a tab label, and also a widget for the contents of the tab, so that they can be added to the tabwidget.
As a start, try something like this:
import sys
from PyQt4 import QtGui, uic
class TestGUI(QtGui.QMainWindow):
def __init__(self):
super(TestGUI, self).__init__()
uic.loadUi('TEST.ui', self)
self.actionAdd_Tab.triggered.connect(self.handleAddTab)
def handleAddTab(self):
contents = QtGui.QWidget(self.tabWidget)
layout = QtGui.QVBoxLayout(contents)
# add other widgets to the contents layout here
# i.e. layout.addWidget(widget), etc
self.tabWidget.addTab(contents, 'Tab One')
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = TestGUI()
window.show()
sys.exit(app.exec_())
QTabWidget's addTab() method, coincidentally named the same, adds a tab.

QComboBox replacing edit text if case differs from existing item

I'm having a problem with QComboBox not allowing me to change the edit
text to anything existing item of differing case.
Example code is below. What I'd like to do is enter 'one' into a combo
box already containing the item 'One' without the side effect of the
text being changed to 'One'. Currently it's changed back to 'One' as
soon as the combo box loses focus.
Disabling AutoCompletionCaseSensitivity works, but it has the side
effect of not being useful (Doesn't eg. show completions for 'one').
I've also tried overriding the focusOutEvent of QComboBox and
restoring the correct text, but then things like copy-paste don't
work. Changing the completer hasn't helped any either.
The fact combo boxes behave this way is detrimental to my app. If
anyone has any ideas (or I missed something obvious), please let me
know.
I'm using Qt 4.6.2 and PyQt 4.7.2 on Ubuntu 10.04, but have
experienced this on other distros/Qt versions above 4.5.
Thanks and Regards
Example Code:
from PyQt4.QtGui import *
from PyQt4.QtCore import SIGNAL, Qt
class Widget(QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
combo = QComboBox()
combo.setEditable(True)
combo.addItems(['One', 'Two', 'Three'])
lineedit = QLineEdit()
layout = QVBoxLayout()
layout.addWidget(combo)
layout.addWidget(lineedit)
self.setLayout(layout)
app = QApplication([])
widget = Widget()
widget.show()
app.exec_()
from PyQt4.QtGui import *
from PyQt4.QtCore import SIGNAL, Qt, QEvent
class MyComboBox(QComboBox):
def __init__(self):
QComboBox.__init__(self)
def event(self, event):
if event.type() == QEvent.KeyPress and event.key() == Qt.Key_Return:
self.addItem(self.currentText())
return QComboBox.event(self, event)
class Widget(QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
combo = MyComboBox()
combo.setEditable(True)
combo.addItems(['One', 'Two', 'Three'])
lineedit = QLineEdit()
layout = QVBoxLayout()
layout.addWidget(combo)
layout.addWidget(lineedit)
self.setLayout(layout)
app = QApplication([])
widget = Widget()
widget.show()
app.exec_()
The only issue with this is that it will allow adding duplicates to your combobox.
I tried adding a self.findText(...) to the if statement but even Qt.MatchExactly | Qt.MatchCaseSensitive
would match "bla", "bLa" and "BLA".
I guess you'll find out.

Categories