I'm learning Python by trying to build a simple plotting application and would like to have two windows in my main screen. I'm using the QSplitter module but am having no luck so far. I'd like the left portion to be used for inputting information via lineEdit() (for now) and the right to show the plot. So far I have
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QWidget, QFrame,QHBoxLayout,QSplitter
from PyQt5.QtWidgets import QMenu, QMenuBar, QLineEdit
class Window(QtWidgets.QMainWindow):
# Main window
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowIcon(QtGui.QIcon("honeywellIcon.png"))
self.setWindowTitle("Materials Database")
self.showMaximized()
self._createMenuBar()
# Splitting the main window
hbox = QHBoxLayout()
leftFrame = QFrame()
leftFrame.setFrameShape(QFrame.StyledPanel)
rightFrame = QFrame()
rightFrame.setFrameShape(QFrame.StyledPanel)
mainSplitLeft = QSplitter(Qt.Horizontal)
lineEdit = QLineEdit()
mainSplitLeft.addWidget(leftFrame)
mainSplitLeft.addWidget(lineEdit)
mainSplitLeft.setSizes([200,500])
mainSplitRight = QSplitter()
mainSplitRight.addWidget(mainSplitLeft)
mainSplitRight.addWidget(rightFrame)
hbox.addWidget(mainSplitRight)
self.setLayout(hbox)
self.show()
# Menu bars on main window
def _createMenuBar(self):
menuBar = self.menuBar()
# Creating 'File' menu option and adding to menuBar
fileMenu = QMenu("&File", self)
menuBar.addMenu(fileMenu)
# Creating 'Options' menu option and adding to menuBar
optionsMenu = menuBar.addMenu("&Options")
menuBar.addMenu(optionsMenu)
# Creating 'View' menu option and adding to menuBar
viewMenu = menuBar.addMenu("&View")
menuBar.addMenu(viewMenu)
# Creating 'Create' menu option and adding to menuBar
createMenu = menuBar.addMenu("&Create")
menuBar.addMenu(createMenu)
# Creating 'Help' menu option and adding to menuBar
helpMenu = menuBar.addMenu("&Help")
menuBar.addMenu(helpMenu)
if __name__ == "__main__":
app = QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec_())
This outputs a window with the menu bars but not the split like I had hoped:
How can I achieve a split window?
My understanding is that a QMainWindow needs to have a centralWidget and you set the layout on the centralWidget. Your QMainWindow should only have one splitter.
Try this:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QWidget, QFrame,QHBoxLayout,QSplitter
from PyQt5.QtWidgets import QMenu, QMenuBar, QLineEdit
class Window(QtWidgets.QMainWindow):
# Main window
def __init__(self, parent=None):
super().__init__(parent)
# self.setWindowIcon(QtGui.QIcon("honeywellIcon.png"))
self.setWindowTitle("Materials Database")
# self.showMaximized()
self._createMenuBar()
self.setCentralWidget(QWidget())
hbox = QHBoxLayout()
rightFrame = QFrame()
rightFrame.setFrameShape(QFrame.StyledPanel)
mainSplit = QSplitter(Qt.Horizontal)
lineEdit = QLineEdit()
mainSplit.addWidget(lineEdit)
#mainSplitLeft.setSizes([200,500])
mainSplit.addWidget(rightFrame)
hbox.addWidget(mainSplit)
self.centralWidget().setLayout(hbox)
self.show()
# Menu bars on main window
def _createMenuBar(self):
menuBar = self.menuBar()
# Creating 'File' menu option and adding to menuBar
fileMenu = QMenu("&File", self)
menuBar.addMenu(fileMenu)
# Creating 'Options' menu option and adding to menuBar
optionsMenu = menuBar.addMenu("&Options")
menuBar.addMenu(optionsMenu)
# Creating 'View' menu option and adding to menuBar
viewMenu = menuBar.addMenu("&View")
menuBar.addMenu(viewMenu)
# Creating 'Create' menu option and adding to menuBar
createMenu = menuBar.addMenu("&Create")
menuBar.addMenu(createMenu)
# Creating 'Help' menu option and adding to menuBar
helpMenu = menuBar.addMenu("&Help")
menuBar.addMenu(helpMenu)
if __name__ == "__main__":
app = QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec_())
If your window layout gets more complicated than this, you might consider doing the layout in Qt Designer.
Related
I am trying to write a PyQt5 application that does the following:
Creates and opens a Main Window. The MainWindow has a function that opens a QFileDialog window.
Function to open QFileDialog can be triggered in two ways (1) from a file menu option called 'Open' (2) automatically, after the Main window is shown.
My problem is that I haven't found a way to get the QfileDialog to automatically open (2) that doesn't cause the application to hang when the main window is closed. Basic example of code can be found below:
import sys
from PyQt5.QtWidgets import (QApplication, QMainWindow, QMenuBar, QWidget,
QHBoxLayout, QCalendarWidget, QScrollArea, QFileDialog, QAction, QFrame)
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import Qt
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.openAction = QAction(QIcon('/usr/share/icons/breeze/places/64/folder-open.svg'), 'Open', self)
self.openAction.triggered.connect(self.openDialog)
self.menubar = QMenuBar(self)
fileMenu = self.menubar.addMenu('&File')
fileMenu.addAction(self.openAction)
self.event_widgets = EventWidgets(self)
self.setMenuBar(self.menubar)
self.setCentralWidget(self.event_widgets)
def openDialog(self):
ics_path = QFileDialog.getOpenFileName(self, 'Open file', '/home/michael/')
class EventWidgets(QWidget):
def __init__(self, parent):
super(EventWidgets, self).__init__(parent)
self.initUI()
def initUI(self):
self.calendar = QCalendarWidget(self)
self.frame = QFrame()
self.scrollArea = QScrollArea()
self.scrollArea.setWidget(self.frame)
horizontal_box = QHBoxLayout()
horizontal_box.addWidget(self.calendar)
horizontal_box.addWidget(self.scrollArea)
self.setLayout(horizontal_box)
if __name__ == '__main__':
app = QApplication(sys.argv)
app_window = MainWindow()
app_window.showMaximized()
app_window.openDialog()
sys.exit(app.exec_())
Code has been tested on KDE Neon and Arch Linux, both have same issue.
I can get round this issue by handling the close event of the Main Window manually - i.e. adding this function to MainWindow:
def closeEvent(self, event):
sys.exit()
But I am not sure a) why this is necessary b) if it is best practice.
I tried your code on macOS Sierra and it works as it's supposed to. However I would propose a different approach to solve your problem.
What you could do is to implement the showEvent() function in your MainWindow class, which is executed whenever a widget is displayed (either using .show() or .showMaximized()) and trigger your custom slot to open the QFileDialog. When doing this you could make use of a single shot timer to trigger the slot with some minimal delay: the reason behind this is that if you simply open the dialog from within the showEvent(), you will see the dialog window but not the MainWindow below it (because the QFileDialog is blocking the UI until the user perform some action). The single shot timer adds some delay to the opening of the QFileDialog, and allows the MainWindow to be rendered behind the modal dialog. Here is a possible solution (not that I made some minor changes to your code, which you should be able to easily pick up):
import sys
from PyQt5 import QtCore
from PyQt5 import QtWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.openAction = QtWidgets.QAction('Open', self)
self.openAction.triggered.connect(self.openDialog)
menuBar = self.menuBar()
fileMenu = menuBar.addMenu('&File')
fileMenu.addAction(self.openAction)
self.event_widgets = EventWidgets(self)
self.setCentralWidget(self.event_widgets)
def showEvent(self, showEvent):
QtCore.QTimer.singleShot(50, self.openDialog)
#QtCore.pyqtSlot()
def openDialog(self):
ics_path = QtWidgets.QFileDialog.getOpenFileName(self, 'Open file', '/Users/daniele/')
class EventWidgets(QtWidgets.QWidget):
def __init__(self, parent):
super(EventWidgets, self).__init__(parent)
self.calendar = QtWidgets.QCalendarWidget(self)
self.frame = QtWidgets.QFrame()
self.scrollArea = QtWidgets.QScrollArea()
self.scrollArea.setWidget(self.frame)
horizontal_box = QtWidgets.QHBoxLayout()
horizontal_box.addWidget(self.calendar)
horizontal_box.addWidget(self.scrollArea)
self.setLayout(horizontal_box)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
app_window = MainWindow()
app_window.showMaximized()
sys.exit(app.exec_())
I've been developing a GUI using PyQt5 and wanted to include a menu bar. When I went to code this feature, however, my menu wouldn't appear. Figuring my understanding on how to implement menu bars in PyQt5 was off, I looked for a pre-existing example online. With some tweaking I developed the following test case:
import sys
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QApplication, QMainWindow, QMenuBar, QAction, qApp
class Example(QMainWindow):
def __init__(self):
super().__init__()
exitAction = QAction(QIcon('exit.png'), '&Exit', self)
exitAction.triggered.connect(qApp.quit)
menubar = self.menuBar()
fileMenu = menubar.addMenu('&Testmenu')
fileMenu.addAction(exitAction)
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
When I run this, however, Testmenu is nowhere to be found.
I have also tried creating the menu bar (and the rest of my GUI layout) in QTCreator before converting the .ui file to an importable .py using pyuic5. I thought this would eliminate some programming mistake on my end, but the menubar still won't show. Any thoughts?
Edit:
Im running this code using Python 3.5 (Anaconda 4.1) from within a Jupyter notebook, version 4.1. I'm also using a Macbook running os 10.1l, PyQt 5.7 and Qt version 5.7.0.
I've realized that the menu bar will become responsive if I click off the application window and then click back onto the window - effectively unfocusing and the focusing the application. Armed with this information I realized that I am not the first to notice this problem (see https://github.com/robotology/yarp/issues/457). Unfortunately, I'm still not sure how to resolve the issue.
It's not a Qt and PyQt5 Bug.
I think your code is zetcode pyqt5 menubar tutorial. I experienced the exact same problem on Mac OS.
First solution is a trick. Use ' &Exit' instead of '&Exit'. Insert a space at the beginning of '&Exit' like this:
...
# exitAction = QAction(QIcon('exit.png'), '&Exit', self) # Not shown
exitAction = QAction(QIcon('exit.png'), ' &Exit', self)
...
The system-wide menubar of macOS reserves keywords such as "Exit", "Quit", and etc. For the same reason, yurisnm's example code shows only the menu items except "Quit" on Mac OS. Actually "Quit" has TextHeuristicRole, so overrides "Quit " behavior in the Application menu. When you click "Quit python" in "Python" menu, it does not quit and just print "quit triggered".
If you must use that name in other menu(e.g. File, Edit), you need to change the action name like above or use QAction::setMenuRole(...) like this:
...
exitAction = QAction(QIcon('exit.png'), '&Exit', self)
print(exitAction.menuRole()) # It prints "1". QAction::TextHeuristicRole
exitAction.setMenuRole(QAction.NoRole)
...
Please read the following, it will be help you.
https://stackoverflow.com/a/11387977/5362866
http://doc.qt.io/qt-5/qmenubar.html#qmenubar-as-a-global-menu-bar
Menubar isn't visible in PyQt5
bar = self.menuBar()
bar.setNativeMenuBar(False)
file = bar.addMenu("File")
file.addAction("New")
NativeMenuBar property specifies whether or not the menubar should be used as a native menubar on platforms that support it. If this property is true, the menubar is used in the native menubar and is not in the window of its parent, if false the menubar remains in the window.
Sample program
import sys
from PyQt5.QtWidgets import QMainWindow, QAction, qApp, QApplication
from PyQt5.QtGui import QIcon
class Menu(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
exitAct = QAction(QIcon('exit.png'), ' &Quit', self)
exitAct.setShortcut('Ctrl+Q')
exitAct.setStatusTip('Exit application')
exitAct.triggered.connect(qApp.quit)
self.statusBar()
menubar = self.menuBar()
menubar.setNativeMenuBar(False)
fileMenu = menubar.addMenu('&File')
fileMenu.addAction(exitAct)
bar = self.menuBar()
file = bar.addMenu("Edit")
file.addAction("New")
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('Simple menu')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Menu()
sys.exit(app.exec_())
If your program is running on Ubuntu, you may find your menu bar on the top of the screen.
If you want to move menu bar to window's title bar, you can toggle the setting at "System setting / Appearance / Behavior / Show the menus for a window / In the window's title bar".
try this:
menubar = QMenuBar()
self.setMenuBar(menubar)
instead of menubar = self.menuBar()
Have you tried the most simple example in the following link tutorialspoint.
Here is the most simple example.
import sys
from PyQt5.QtWidgets import QHBoxLayout, QAction, QApplication, QMainWindow
class menudemo(QMainWindow):
def __init__(self, parent = None):
super(menudemo, self).__init__(parent)
bar = self.menuBar()
file = bar.addMenu("File")
file.addAction("New")
save = QAction("Save",self)
save.setShortcut("Ctrl+S")
file.addAction(save)
edit = file.addMenu("Edit")
edit.addAction("copy")
edit.addAction("paste")
quit = QAction("Quit",self)
file.addAction(quit)
file.triggered[QAction].connect(self.processtrigger)
self.setWindowTitle("menu demo")
def processtrigger(self, q):
print(q.text()+" is triggered")
def main():
app = QApplication(sys.argv)
ex = menudemo()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Under MacOS, an application menu appears at the top of the screen. I managed to get the Quit menu option to appear in the above example by prepending the string "Quit" with a null character as follows:
close = QAction("\0Quit",self)
close.setShortcut("Ctrl+Q")
file.addAction(close)
It seems macOS somehow intercepts the menu items called "Quit" or "Exit".
You can happily use "Close" or "Leave" without the workaround.
This is the code I am using and the button doesn't show and it only shows a blank window. There is no error in the console.
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import *
import sys
def start():
app = QApplication(sys.argv)
w = QWidget()
w.resize(128,102)
w.move(0, 0)
w.setWindowTitle('Simple')
btn = QtWidgets.QPushButton("Hi")
btn.move(50, 50)
btn.resize(btn.sizeHint())
w.show()
sys.exit(app.exec_())
start()
This is the window it shows
Try passing the parent argument to the constructor. The parent argument causes the button to be owned by Qt, not PyQt. btn = QtWidgets.QPushButton("Hi", w) should work.
Any widget you want to be shown needs to be parented, either directly or indirectly, to the widget you want it to appear in.
The common way to do this is by assigning your widget a layout and adding other widgets or sublayouts to it.
widget = QtWidgets.QWidget()
button = QtWidgets.QPushButton('Hi')
layout = QtWidgets.QVBoxLayout(widget) # Parents layout to widget
layout.addWidget(button)
widget.show()
In this example, widget is indirectly assigned as the parent to button through layout
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import *
import sys
def start():
app = QApplication(sys.argv)
w = QWidget()
w.resize(128,102)
w.move(0, 0)
w.setWindowTitle('Simple')
btn = QtWidgets.QPushButton (w)
btn.move(50, 50)
btn.resize(btn.sizeHint())
btn.setText ('Hi')
w.show()
sys.exit(app.exec_())
start()
I'm a beginner in PyQt and I have an image known as add.gif. I need to put this image in a QPushButton but I don't know how.
Example:
from PyQt4 import QtGui, QtCore
class Window(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.button = QtGui.QPushButton('', self)
self.button.clicked.connect(self.handleButton)
self.button.setIcon(QtGui.QIcon('myImage.jpg'))
self.button.setIconSize(QtCore.QSize(24,24))
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.button)
def handleButton(self):
pass
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
Here is the same example from #NorthCat but for PyQt5:
from PyQt5 import QtGui, QtCore
from PyQt5.QtWidgets import QWidget, QApplication, QPushButton, QVBoxLayout
class Window(QWidget):
def __init__(self):
QWidget.__init__(self)
self.button = QPushButton('', self)
self.button.clicked.connect(self.handleButton)
self.button.setIcon(QtGui.QIcon('myImage.jpg'))
self.button.setIconSize(QtCore.QSize(200,200))
layout = QVBoxLayout(self)
layout.addWidget(self.button)
def handleButton(self):
pass
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
Assuming pyqt supports gif pictures, this should work
icon = QtGui.QPixmap('add.gif')
button = QtGui.QPushButton()
button.setIcon(icon)
QPushButton
Push buttons display a textual label, and optionally a small icon.
These can be set using the constructors and changed later using
setText() and setIcon(). If the button is disabled, the appearance of
the text and icon will be manipulated with respect to the GUI style to
make the button look "disabled".
How do I create a drop-down widget, such as a drop-down QLabel, drop-down QTextBrowser, etc.?
For example, I log information in a QTextBrowser, but I don't want it taking up space on the screen. So I want to be able to click a QToolbutton and have a scrollable QTextBrowser drop-down. (A QComboBox would work too, but I can't just add each event as a separate item - I need the text to wrap, not be elided. Thus a drop-down QTextBrowser.)
Or, for example, I want a drop-down QLabel containing a picture, etc...
Create a QWidgetAction for the drop-down widget, and add it to the tool-button's menu:
from PyQt4 import QtGui, QtCore
class Window(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
layout = QtGui.QHBoxLayout(self)
self.button = QtGui.QToolButton(self)
self.button.setPopupMode(QtGui.QToolButton.MenuButtonPopup)
self.button.setMenu(QtGui.QMenu(self.button))
self.textBox = QtGui.QTextBrowser(self)
action = QtGui.QWidgetAction(self.button)
action.setDefaultWidget(self.textBox)
self.button.menu().addAction(action)
layout.addWidget(self.button)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.resize(100, 60)
window.show()
sys.exit(app.exec_())