I'm in a bit of a bind because I have been experimenting on creating a GUI with pyqt4 through python.
In QDialog when you open a window, it automatically focus on a QPushButton and you can press Tab to cycle through the QDialog and press enter on the selected QPushButton or menuBar etc. but how do I do it on QMainWindow? Setting
button1.setAutoDefault(True)
does work but cycling selection in QMainWindow(with Tab) does select other Qbject but pressing enter does not work
unless I re-select the button1 through Tab(Enter only works on the default button1). I've tried reading the documentation but maybe I missed something?
Here's my code:
class Window(QtGui.QMainWindow):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
self.setGeometry(750, 450, 400, 200)
self.setFixedSize(self.size())
btn1 = QtGui.QPushButton("OK", self)
btn1.clicked.connect(self.trans_num)
btn1.resize(btn1.minimumSizeHint())
btn1.move(210,171)
btn1.setStatusTip("Magic")
btn1.setDefault(True)
btn1.setAutoDefault(True)
btn2 = QtGui.QPushButton("Exit", self)
btn2.clicked.connect(self.close_application)
btn2.resize(btn2.minimumSizeHint())
btn2.move(305,171)
btn2.setStatusTip("Exit Application")
self.show()
Related
I've tried to put a MenuBar but it doesn't appear, and I don't know what I doing wrong.
from PyQt4 import QtGui
import sys
class Window(QtGui.QMainWindow):
def __init__(self):
super(Window, self).__init__()
self.setWindowTitle("IDE")
self.initUI
def initUI(self):
grid = QtGui.QGridLayout(self)
menuBar = QtGui.QMenuBar(self)
self.fileMenu = menuBar.addMenu("File")
grid.addWidget(menuBar, 0, 0)
self.setLayout(grid)
and the result:
You'll need to set the menubar on the main window
self.setMenuBar(menuBar)
In many cases, you don't need to create the menubar manually, you can just call .menuBar() on the main window and it will return the current one or create one if it doesn't exist. This is the preferred way if there's a chance your .ui file contains a menubar and menubar items.
menubar = self.menuBar()
Also, you can't add QMenuBars to layouts - from the docs:
There is no need to lay out a menu bar. It automatically sets its own geometry to the top of the parent widget and changes it appropriately whenever the parent is resized.
I am using PyQt to create a desktop application. I am trying to create a button using hbox and vbox, but it doesn't display unless I give the specific command:
button1 = QtGui.QPushButton("Exit", self)
But, by doing this, the vbox and hbox functionality doesn't seem to function.
I need the button to be on the bottom-right corner of the window, which stays there even after window-resize.
With this code, it is positioned on the top-left corner.
from PyQt4 import QtGui, QtCore
import sys
class Trial(QtGui.QMainWindow):
def __init__(self):
super(Trial,self).__init__()
self.createUI()
def createUI(self):
button1 = QtGui.QPushButton("Exit",self)
button1.clicked.connect(self.close)
hbox = QtGui.QHBoxLayout()
hbox.addStretch(1) #stretches it to the right end of the page
hbox.addWidget(button1)
vbox = QtGui.QVBoxLayout()
vbox.addStretch(1) #stretches it to the bottom end of the page
vbox.addLayout(hbox)
self.setLayout(vbox)
button1.resize(button1.sizeHint())
self.setGeometry(300,200,750,450)
self.setWindowTitle('Testing')
self.show()
def main():
app= QtGui.QApplication(sys.argv)
w=Trial()
sys.exit(app.exec_())
if __name__=='__main__':
main()
If I use button1.move(420, 400), it moves the button to the position I want, but it doesn't stay there when I re-size the application window.
The example code doesn't work because you are trying to set a layout on the main window, which already has a layout.
Instead, you need to add a central widget, and then set the layout on that:
def createUI(self):
self.setCentralWidget(QtGui.QWidget(self))
...
vbox.addLayout(hbox)
self.centralWidget().setLayout(vbox)
self.setGeometry(300,200,750,450)
...
By pressing a QPushButton in my QDialog window I want to open a new QWidget window.
My code:
from PyQt4 import QtGui
import sys
class MainWindow(QtGui.QWidget):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setWindowTitle("Main Window")
class FirstWindow(QtGui.QDialog):
def __init__(self, parent=None):
super(FirstWindow, self).__init__(parent)
self.createWindow()
def createWindow(self):
btn = QtGui.QPushButton('Open New Window', self)
btn.move(10, 10)
self.openNewWindow = MainWindow(self)
btn.clicked.connect(self.openMainWin)
self.setGeometry(250,250, 150,50)
self.setWindowTitle("First Window")
self.show()
def openMainWin(self):
self.openNewWindow.show()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
firstwin = FirstWindow()
sys.exit(app.exec_())
When I run the code nothing happens by pressing the button.
But when I change the class from
class MainWindow(QtGui.QWidget) to
class MainWindow(QtGui.QDialog) or class MainWindow(QtGui.QMainWindow)
it works!
What am I doing wrong?! Please assist me.
When you instantiate MainWindow you pass in a parent. Qwidget only makes a new window if you don't specify a parent.
This is of course deliberate. If QWidgets with parents were shown in new windows, then you could never build a GUI. Imagine having every widget in it's own window!
QMainWindow and QDialog are specifically designed to both have a parent, and create a new window. You should use them.
Hello I am working on data archive program with python 2.7. I have one mainWindow and there is some elements (Buttons, text lines etc.) Clicking a button open a dialog form page. User select their answer on that dialog page. Dialog page has a button named 'save'. When clicking save button dialog class saving user's selections to database. I want to do, when user clicked to save button on dialog, It will enable some elements on the mainWindow which is not enabled. I am doing this with these codes entering to dialog class and save button function:
self.ui.onceBut.setEnabled(True) etc.
But I am taking an error:
AttributeError: 'onceDlg' object has no attribute 'onceBut'
onceDlg is dialog pages class name.
How can I solve this and I can do what I want? Thanks in advance.
self in self.ui.onceBut.setEnabled(True) refers to dialog, so you get error because your onceBut is in your mainWindow not in onceDlg dialog.
Solution: as #Radio say - Communication between components in Qt are often done using signals and slots, but it's not the only way.
Easier way is to simply pass main window to dialog window, so you can manipulate with it's buttons, or whatever you want, inside dialog window. In next example I've done that in line dialog = Dialog(self), where self refers to MainWindow and it is used as mainWin inside Dialog. Run it, click on first button, dialog will show, click save button in dialog and second button in main will be changed and disabled.
I hope I've helped you.
import sys
from PyQt4 import QtCore, QtGui
class Dialog(QtGui.QDialog):
def __init__(self, mainWin):
QtGui.QDialog.__init__(self,mainWin)
self.setWindowTitle(self.tr("Dialog window"))
self.main = mainWin
button = QtGui.QPushButton()
button.setText( "Save (disable dummy button)" )
layout = QtGui.QVBoxLayout()
layout.addWidget(button)
self.setLayout(layout)
self.connect(button, QtCore.SIGNAL("clicked()"), self.save)
self.resize(200, 100)
def save(self):
self.main.button2.setEnabled(False)
self.main.button2.setText( "changed from dialog" )
class MainWindow(QtGui.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowTitle(self.tr("Main window"))
self.button1 = QtGui.QPushButton()
self.button2 = QtGui.QPushButton()
self.button1.setText( "Open dialog" )
self.button2.setText( "Dummy" )
layout = QtGui.QVBoxLayout()
layout.addWidget(self.button1)
layout.addWidget(self.button2)
self.window = QtGui.QWidget()
self.window.setLayout(layout)
self.setCentralWidget(self.window);
self.connect(self.button1, QtCore.SIGNAL("clicked()"), self.showDialog)
self.resize(360, 145)
def showDialog(self):
dialog = Dialog(self)
dialog.show()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
main = MainWindow()
main.show();
sys.exit(app.exec_())
In this sample of code:
from PyQt4.QtGui import QDialog, QPushButton, QRadioButton, QHBoxLayout, QApplication, QButtonGroup
import sys
class Form(QDialog):
def __init__(self, parent=None):
super(Form, self).__init__(parent=None)
button = QPushButton('Button')
self.radiobutton1 = QRadioButton('1')
self.radiobutton2 = QRadioButton('2')
#self.group = QButtonGroup()
#self.group.addButton(self.radiobutton1)
#self.group.addButton(self.radiobutton2)
#self.group.setExclusive(False)
layout = QHBoxLayout()
layout.addWidget(button)
layout.addWidget(self.radiobutton1)
layout.addWidget(self.radiobutton2)
self.setLayout(layout)
button.clicked.connect(self.my_method)
def my_method(self):
self.radiobutton1.setChecked(False)
self.radiobutton2.setChecked(False)
app = QApplication(sys.argv)
form = Form()
form.show()
app.exec_()
When the button clicked I expect the selected radioButton to be unchecked, but that never happens. If I uncomment the comment lines and run the code, then I can uncheck radioButtons. But another problem occurs. Because the group is not exclusive, I can set both radioButtons checked something that must not happens.
What should I do to be able to unckeck the buttons while only one button at a time can be selected?
This feels like cheating, but it works:
import sys
import PyQt4.QtGui as QtGui
class Form(QtGui.QDialog):
def __init__(self, parent=None):
super(Form, self).__init__(parent)
button = QtGui.QPushButton('Button')
button.clicked.connect(self.my_method)
self.radiobutton1 = QtGui.QRadioButton('1')
self.radiobutton2 = QtGui.QRadioButton('2')
layout = QtGui.QHBoxLayout()
layout.addWidget(button)
layout.addWidget(self.radiobutton1)
layout.addWidget(self.radiobutton2)
self.setLayout(layout)
self.group = QtGui.QButtonGroup()
self.group.addButton(self.radiobutton1)
self.group.addButton(self.radiobutton2)
def my_method(self):
self.group.setExclusive(False)
self.radiobutton1.setChecked(False)
self.radiobutton2.setChecked(False)
self.group.setExclusive(True)
app = QtGui.QApplication(sys.argv)
form = Form()
form.show()
app.exec_()
As you've pointed out, when self.group.setExclusive(False) is set, you can untoggle both radio buttons.
And when self.group.setExclusive(True), only one radio button can be set.
So my_method simply calls self.group.setExclusive(False) so it can unset both radio buttons, then resets self.group.setExclusive(True).
PS. I think parent should not be set to None on this line:
super(Form, self).__init__(parent = None)
since if a non-trivial parent is sent to Form, you would probably want to pass that parent on to QDialog.__init__.
To anyone looking for a simple fix to this very annoying problem, connect each button to a slot that controls the CheckState of the other buttons.
Simply add the list of buttons you want to a QButtonGroup, get the list of buttons, check that the sender is not the same button, and uncheck others.
Assuming that you instantiate your buttons in a loop, you can easily implement this:
self.bg = QButtonGroup()
self.bg.setExclusive(False)
for button in list_of_buttons:
self.bg.addButton(button)
button.clicked.connect(self.uncheck_other_buttons)
def uncheck_other_btns(self):
for button in self.bg.buttons(): # returns the list of all added buttons
if self.sender() != button: # in PyQt5, button.objectName() fails if name isn't set,
# instead, simply check that the signal sender() object
# is not the same object as the clicked button
button.setChecked(False) # then set all other buttons to be unchecked