I am trying to package my GUI application into an application using FMan FBS. I am able to create and open the basic plain application; however, when I try to integrate my own code into the default code, once I try to run the app it closes instantly without running.
Here is the default code:
from fbs_runtime.application_context.PyQt5 import ApplicationContext
from PyQt5.QtWidgets import QMainWindow
import sys
if __name__ == '__main__':
# 1. Instantiate ApplicationContext
appctxt = ApplicationContext()
window = QMainWindow()
window.resize(250, 150)
window.show()
# 2. Invoke appctxt.app.exec_()
exit_code = appctxt.app.exec_()
sys.exit(exit_code)
and this works. However, my application works a lot with layouts and so I use a QWidget as my window instead of a QMainWindow. I believe this may be why the program can't be opened when packaged.
Here is a sample of my code:
class Interface:
def __init__(self):
self.app = QApplication([])
def main(self):
window = QWidget()
window.setGeometry(550, 300, 850, 550)
window.setWindowTitle("GUI")
layout = QGridLayout()
self.app.setStyle("Fusion")
tabs = QTabWidget()
tab1 = QWidget()
tab2 = QWidget()
tab3 = QWidget()
tabs.addTab(tab1, "Tab1")
tabs.addTab(tab2, "Tab2")
layout1 = QGridLayout()
layout2 = QGridLayout()
# ...
tab1.setLayout(layout1)
tab2.setLayout(layout2)
window.setLayout(layout)
window.show()
self.app.exec_()
I am able to run my program fine with "FBS run"; however, when actually packing the application with "FBS freeze/ FBS installer", it doesn't open properly. It does work with the default code which leads me to believe that changing it from QMainWindow to QWidget is causing it to not work
The logic is similar the fbs API already has a QApplication created so you must create it, in this case you just have to make the following modification to the example provided by fbs:
from fbs_runtime.application_context.PyQt5 import ApplicationContext
from PyQt5.QtWidgets import QWidget, QTabWidget, QGridLayout
import sys
class Interface:
def main(self):
self.window = QWidget()
self.window.setGeometry(550, 300, 850, 550)
self.window.setWindowTitle("GUI")
layout = QGridLayout()
tabs = QTabWidget()
tab1 = QWidget()
tab2 = QWidget()
tab3 = QWidget()
tabs.addTab(tab1, "Tab1")
tabs.addTab(tab2, "Tab2")
layout1 = QGridLayout()
layout2 = QGridLayout()
# ...
tab1.setLayout(layout1)
tab2.setLayout(layout2)
self.window.setLayout(layout)
self.window.show()
if __name__ == '__main__':
# 1. Instantiate ApplicationContext
appctxt = ApplicationContext()
interface = InterFace()
inteface.main()
appctxt.app.setStyle("Fusion")
# 2. Invoke appctxt.app.exec_()
exit_code = appctxt.app.exec_()
sys.exit(exit_code)
Related
I am new to PyQt and Qt at all and I have a problem with window rendering or updating or how to call it. Problem is that when I call QWidget.show(), none of added components after are displayed. Here is a simple code, where in init(), there is called self.show(). First QLabel item is displayed and the second one is not. What am I doing wrong?
Code:
from PyQt6.QtWidgets import QApplication, QWidget, QLabel
import sys
class MyGui(QWidget):
box = {}
def __init__(self) -> None:
super().__init__()
self.setFixedSize(200, 400)
self.setStyleSheet("background-color:#000000")
self.box["top"] = QLabel(self)
self.box["top"].setFixedSize(200, 200)
self.box["top"].setStyleSheet("background-color:red")
self.box["top"].move(0,0)
self.show()
self.box["botom"] = QLabel(self)
self.box["botom"].setFixedSize(200, 200)
self.box["botom"].setStyleSheet("background-color:green")
self.box["botom"].move(0,200)
if __name__ == "__main__":
app = QApplication(sys.argv)
my_app = MyGui()
my_app.show()
try:
sys.exit(app.exec())
except SystemExit:
print("Closing window..")
Screenshots of GUI window:
With self.show()
Without self.show()
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 am new in Qt (PyQt) and I am trying to make an app whose functions will be executed from menubars/system trays. A perfect example is show here:
I cannot find a good resource on how I can do this. Can someone advice.
Thanks.
I think you are looking for working with QMenu and QMainWindow for the menu part, at least.
Here you can find a C++ example:
Menus Example
and here a PyQt4 example:
Menus and Toolbars in PyQt4
Here is the code inline for your convenience:
import sys
from PyQt4 import QtGui
class Example(QtGui.QMainWindow):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
exitAction = QtGui.QAction(QtGui.QIcon('exit.png'), '&Exit', self)
exitAction.setShortcut('Ctrl+Q')
exitAction.setStatusTip('Exit application')
exitAction.triggered.connect(QtGui.qApp.quit)
self.statusBar()
menubar = self.menuBar()
fileMenu = menubar.addMenu('&File')
fileMenu.addAction(exitAction)
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('Menubar')
self.show()
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
As for the QSystemTrayIcon part, you could write something like this:
def main():
app = QtGui.QApplication(sys.argv)
w = QtGui.QWidget()
trayIcon = QtGui.QSystemTrayIcon(QtGui.QIcon("Bomb.xpm"), w)
menu = QtGui.QMenu(parent)
exitAction = menu.addAction("Foo")
trayIcon.setContextMenu(menu)
trayIcon.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
I have a problem to set a new layout in my QWidget object. I start to set one type of layout when the app exec, and I want to change it when the button is pressed with a new layout. In the documentation of PySide I read this:
Sets the layout manager for this widget to layout.
If there already is a layout manager installed on this widget,
PySide.QtGui.QWidget won’t let you install another. You must first
delete the existing layout manager (returned by
PySide.QtGui.QWidget.layout() ) before you can call
PySide.QtGui.QWidget.setLayout() with the new layout.
But how can I delete the existing layout manager? What are the methods which I must apply on my QWidget object?
If you're new to PySide/PyQt, see the Layout Management article in the documentation for an overview of Qt's layout system.
For your specific example, you will need a method to recursively remove and delete all the objects from a layout (i.e. all its child widgets, spacer-items and other layouts). And also a method to build and add the new layout.
Here's a simple demo:
from PySide import QtCore, QtGui
class Window(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
layout = QtGui.QVBoxLayout(self)
self.changeLayout(QtCore.Qt.Vertical)
self.button = QtGui.QPushButton('Horizontal', self)
self.button.clicked.connect(self.handleButton)
layout.addStretch()
layout.addWidget(self.button)
def handleButton(self):
if self.button.text() == 'Horizontal':
self.changeLayout(QtCore.Qt.Horizontal)
self.button.setText('Vertical')
else:
self.changeLayout(QtCore.Qt.Vertical)
self.button.setText('Horizontal')
def changeLayout(self, direction):
if self.layout().count():
layout = self.layout().takeAt(0)
self.clearLayout(layout)
layout.deleteLater()
if direction == QtCore.Qt.Vertical:
layout = QtGui.QVBoxLayout()
else:
layout = QtGui.QHBoxLayout()
for index in range(3):
layout.addWidget(QtGui.QLineEdit(self))
self.layout().insertLayout(0, layout)
def clearLayout(self, layout):
if layout is not None:
while layout.count():
item = layout.takeAt(0)
widget = item.widget()
if widget is not None:
widget.deleteLater()
else:
self.clearLayout(item.layout())
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.setGeometry(500, 300, 300, 100)
window.show()
sys.exit(app.exec_())
I'm kinda new to PySide.I have a main window object which shows one widget at a time. I've been trying to change the central widget of the QMainWindow class in order to replace the visible Widget in the window when pressing a button. The problem is that the button pressed is in the Widget class, not in the main window class.
say...
class App(QtGui.QMainWindow):
def __init__(self):
super(App, self).__init__()
self.initUI()
def initUI(self):
self.statusBar().showMessage('Listo.') #Status Bar
self.login_screen = LoginScreen()
self.logged_in_screen = LoggedInScreen()
self.setCentralWidget(self.login_screen)
self.setGeometry(300, 300, 450, 600) #Window Size
self.setWindowTitle('PyTransactio - Client') #Window Title
self.setWindowIcon(QtGui.QIcon('icon.png')) #App Icon
self.show()
The pressed button is in the login_screen instance. The method called when the button is clicked is inside the LoginScreen class:
def login(self):
""" Send login data to the server in order to log in """
#Process
self.setParent(None)
Setting the parent widget to None removes the widget (login_screen) from the main window. What should I do in order to get another widget (e.g. logged_in_screen) as the central widget of the main window when the loginButton (inside the login_screen widget) is pressed?
Maybe the login method should be inside the main window class? If so, how can I connect the buttons pressed in login_screen with the main window's method?
You may use a QStackedWidget as central widget and add both the log-in screen and "logged-in" screen to it.
An example usage:
from PyQt4 import QtCore, QtGui
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.central_widget = QtGui.QStackedWidget()
self.setCentralWidget(self.central_widget)
login_widget = LoginWidget(self)
login_widget.button.clicked.connect(self.login)
self.central_widget.addWidget(login_widget)
def login(self):
logged_in_widget = LoggedWidget(self)
self.central_widget.addWidget(logged_in_widget)
self.central_widget.setCurrentWidget(logged_in_widget)
class LoginWidget(QtGui.QWidget):
def __init__(self, parent=None):
super(LoginWidget, self).__init__(parent)
layout = QtGui.QHBoxLayout()
self.button = QtGui.QPushButton('Login')
layout.addWidget(self.button)
self.setLayout(layout)
# you might want to do self.button.click.connect(self.parent().login) here
class LoggedWidget(QtGui.QWidget):
def __init__(self, parent=None):
super(LoggedWidget, self).__init__(parent)
layout = QtGui.QHBoxLayout()
self.label = QtGui.QLabel('logged in!')
layout.addWidget(self.label)
self.setLayout(layout)
if __name__ == '__main__':
app = QtGui.QApplication([])
window = MainWindow()
window.show()
app.exec_()
If you do not want to use this widget, then I think you'll have to call QMainWindow.setCentralWidget every time you change the central widget.
As to where the login method should be, it depends. Probably you could define a simple interface for your mainwindow to add/remove/show specific central widgets, and call it from the login method of LoginScreen. In this way the LoginScreen class does not have to know about implementation details such as if the central widget is actually a QStackedWidget or this thing is done in an other way.
You can use QMainWindow.setCentralWidget to do this (repeatedly):
#! /usr/bin/env python3
from PySide import QtGui
from PySide import QtCore
import sys
app = QtGui.QApplication(sys.argv)
mw = QtGui.QMainWindow()
w2 = QtGui.QWidget()
pb = QtGui.QPushButton('push me', w2)
l1 = QtGui.QLabel('orig')
l2 = QtGui.QLabel('changed')
mw.setCentralWidget(l1)
pb.clicked.connect(lambda: mw.setCentralWidget(l2))
mw.show()
w2.show()
sys.exit(app.exec_())