When I made a GUI i used different classes to construct the main UI Screen.
My code has the following structure:
This is the GUI itself:
The bottum_buttons.py creates the 3 buttons at the buttom. This is the code that is inside bottum_buttons.py:
import Advanced_window
from PyQt5 import QtCore
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from datetime import datetime
import calendar
import sys
class bottum_buttons(QWidget):
def __init__(self):
QWidget.__init__(self)
# Create Layout
self.bottum_box = QHBoxLayout()
# Creating Buttons
self.cancel_button = QPushButton("Cancel")
self.run_button = QPushButton("Run")
self.advanced_button = QPushButton("Advancend Options")
self.add_items_to_layout()
self.create_button_functions()
def add_items_to_layout(self):
self.bottum_box.addWidget(self.cancel_button)
self.bottum_box.addWidget(self.run_button)
self.bottum_box.addWidget(self.advanced_button)
def create_button_functions(self):
self.cancel_button.clicked.connect(self.close)
self.advanced_button.clicked.connect(Advanced_window.advancedwindows)
def return_bottum_buttons(self):
return self.bottum_box
My code that actually constructs the GUI is inside main_screen.py.
The following code is inside this file:
from Ui_Elements import option_box
from Ui_Elements import path_box
from Ui_Elements import bottum_buttons
from Ui_Elements import command_output
from PyQt5 import QtCore
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from datetime import datetime
import calendar
import sys
class main_screen(QDialog):
def __init__(self):
QDialog.__init__(self)
self.setWindowTitle("Robo Tool")
self.main_frame = QVBoxLayout()
# Get UI Elements
path_ui = path_box.path_box()
option_ui = option_box.option_box()
command_ui = command_output.command_box()
bottum_ui = bottum_buttons.bottum_buttons()
self.path = path_ui.return_path_box()
self.option_box = option_ui.return_options_box()
self.command_output = command_ui.return_command_box()
self.bottum_buttons = bottum_ui.return_bottum_buttons()
self.setLayout(self.add_item_to_frame(self.main_frame))
def add_item_to_frame(self, main_frame):
main_frame.addLayout(self.path)
main_frame.addLayout(self.option_box)
main_frame.addLayout(self.command_output)
main_frame.addLayout(self.bottum_buttons)
return main_frame
app = QApplication(sys.argv)
dialog = main_screen()
dialog.show()
app.exec_()
Now the problem is. When i start the main_screen.py the GUI shows up as the picture provided. But the buttons don't work. I dont get any error message. They're still clickable but they dont run the command i provided. Can somebody please help me out.
I don't know what Advanced_window.advancedwindows() is supposed to do, but your cancel button is connected to bottom_buttons.close, not to main_screen.close which I assume is what you want. Since bottom_buttons has no knowledge in advance about which window is supposed to be closed, you can't really connect the button to the close method of a predefined widget. What you could do however is to use self.window().close() instead which would close the next-level ancestor widget of bottom_buttons that has a window. For this, you would need to set the layout of bottom_bottuns to self.bottom_box and add the whole widget to the layout of main_screen rather than just the layout.
This would mean that you would get something like this for bottom_buttons:
class bottum_buttons(QWidget):
def __init__(self):
.... as before ....
# set bottom_box as layout of self
self.setLayout(self.bottom_box)
....
def create_button_functions(self):
# connect cancel button to close method of top level ancestor widget
self.cancel_button.clicked.connect(lambda: self.window().close())
....
And for main_screen:
class main_screen(QDialog):
def __init__(self):
.... as before ....
# set self.bottom_buttons to bottom_buttons widget rather than the layout
self.bottum_buttons = bottum_ui
self.setLayout(self.add_item_to_frame(self.main_frame))
def add_item_to_frame(self, main_frame):
...
# add bottom_buttons widget to the layout.
main_frame.addWidget(self.bottum_bottons)
return main_frame
Related
So i am making a GUI to identify seagulls.
I have made some QMainWindow's and would like the user to nagviate through these using buttons.
The first window works fine, and the user gets to the next page.
However, when clicking on buttons on page 2, nothing works, not even printing a simple statement. I am new to this and i am doing something wrong. I tried messing with init but am at a loss.
I am using a function
def openNewPage(self,b):
NewPage = b.text()
uic.loadUi(f"{NewPage}.ui",self)
self.show
to open a new page by having the buttons clicked on by the user have the name of the next file to be opened.
For example: the button for white head has the text "WhiteHead"
and will the open the file WhiteHead.ui
example:
self.bWhiteHead.clicked.connect(lambda:self.openNewPage(self.bWhiteHead))
Please help me understand why buttons work in one window and not in the next, thank you.
Here is the code:
import sys
from PyQt6.QtWidgets import QApplication, QMainWindow
from PyQt6.QtGui import QIcon
from PyQt6.QtCore import Qt
from PyQt6 import uic
import time
class MyApp(QMainWindow):
def __init__(self):
super().__init__()
uic.loadUi("SeagullPage1.ui",self)
self.setWindowTitle("SEAGULL IDENTIFIER")
self.bBlackHead.clicked.connect(lambda:self.openNewPage(self.bBlackHead))
self.bWhiteHead.clicked.connect(lambda:self.openNewPage(self.bWhiteHead))
def openNewPage(self,b):
NewPage = b.text()
uic.loadUi(f"{NewPage}.ui",self)
self.show
class WhiteHead(QMainWindow):
def __init__(self):
super().__init__
self.setWindowTitle("SEAGULL IDENTIFIER2")
self.BlackFeetButton.clicked.connect(lambda:self.openNewPage(self.BlackFeetButton))
self.PinkFeetButton.clicked.connect(lambda:self.openNewPage(self.PinkFeetButton))
self.YellowFeetButton.clicked.connect(lambda:self.openNewPage(self.YellowFeetButton))
def openNewPage(self,b):
print("hey")
NewPage = b.text()
uic.loadUi(f"{NewPage}.ui",self)
self.show
class YellowFeet(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("SEAGULL IDENTIFIER3")
self.RedBeakButton.clicked.connect(lambda:self.openNewPage(self.RedBeakButton))
self.NonReadBeakButton.clicked.connect(lambda:self.openNewPage(self.NonReadBeakButton))
def openNewPage(self,b):
print("hey")
NewPage = b.text()
uic.loadUi(f"{NewPage}.ui",self)
self.show
if __name__ == "__main__":
app = QApplication(sys.argv)
myApp = MyApp()
myApp.show()
app.exec()
#sys.exit(app.exec_())
I wrote a plugin in PyQGIS, which contains several Ui's (using QT Designer). When I run the code in the QGIS Python console, it works wonderfully. Now I would like to make it available internally for the company as a classic QGIS plugin (start in menu bar). It always worked well with previous plugins, but there was always only one Ui.
At its core there are three important files. 1. __ init __.py, 2. geowerkzeug.py, which is responsible for starting from the menu, and 3. functionality.py, which contains all my functions.
##__init__.py
from Plugin.geowerkzeug import GeoWerkzeug
def classFactory(iface):
plugin = GeoWerkzeug(iface)
return plugin
Now the geowerkzeug.py:
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from plugin.functionality import *
from qgis.utils import iface
import os
class GeoWerkzeug:
def __init__ (self, iface):
self.iface = iface
def initGui (self):
self.startButton = QAction("Plugin starten", self.iface.mainWindow())
self.iface.addPluginToMenu('Plugin', self.startButton)
self.startButton.triggered.connect(self.maskeAufrufen)
def unload (self):
self.iface.removePluginMenu('Plugin', self.startButton)
def maskeAufrufen (self):
self.gui = MainWindow(self)
dock_widget = QDockWidget("Plugin", self.iface.mainWindow())
dock_widget.setWidget(self.gui)
self.iface.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock_widget)
dock_widget.setAllowedAreas(QtCore.Qt.RightDockWidgetArea)
self.gui.show()
Up to here it works. MainWindow is the first class on functionality.py. The window will appear. But if I click on a button to switch to the next Ui (class), the Ui does not change. I have a total of 17 Ui's in my plugin. Here I only show two classes as an example.
Now the functionality.py:
from PyQt5.uic import loadUi
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import *
from PyQt5 import *
from qgis.core import *
from qgis.utils import iface
from qgis.gui import *
import processing
from PyQt5 import uic
import os
pluginPath = os.path.dirname(__file__)
uiPath = os.path.join(pluginPath, 'mainwindow.ui')
uiPath_second_window = os.path.join(pluginPath, 'window2.ui')
WIDGET, BASE = uic.loadUiType(uiPath)
widget = QDockWidget()
class MainWindow(BASE, WIDGET):
def __init__(self, parent=None):
super(MainWindow, self).__init__()
self.gui = loadUi(uiPath, self)
self.window_second.clicked.connect(self.next_window)
def next_window(self):
window_the_second=Second_window()
widget.setWidget(window_the_second)
class Second_window(BASE, WIDGET):
def __init__(self):
super(Second_window, self).__init__()
self.gui = loadUi(uiPath_second_window , self)
My biggest problem with understanding is how to correctly link my code from functionality.py (which runs in the console) with the other two files. The next problem is that I don't even get an error message that I could build on. The plugin is in the menu bar and it can be started, but after that I can't get any further. I hope my explanations are understandable.
The main issue which causes the second window not to appear, is that you never show the QDockWidget. With widget.setWidget(window_the_second) you set the content, but it doesn't make the window appear.
In your method that shows the first window, add the dockwidget with self.iface.addDockWidget(QtCore.Qt.RightDockWidgetArea, widget)
then set your first window as content of that dockwidget (widget.setWidget(self.gui)).
In general, you got some things a bit mixed up, so I'll try to clarify two points.
The contents of a window are set by subclassing the results of uic.loadUiType. In order to have a second window display your second ui, you can't sublass the same BASE and WIDGET. Call uic.loadUiType for each of your UI-Files instead.
You are missing a call to setupUi() to initialize the UI. Then you can also get rid of any loadUi.
Implementing my advices then results in the following:
WIDGET, BASE = uic.loadUiType('1.ui')
WIDGET2, BASE2 = uic.loadUiType('2.ui')
widget = QDockWidget()
class GeoWerkzeug:
def __init__ (self, iface):
self.iface = iface
def initGui (self):
self.startButton = QAction("Plugin starten", self.iface.mainWindow())
self.iface.addPluginToMenu('Plugin', self.startButton)
self.startButton.triggered.connect(self.maskeAufrufen)
def unload (self):
self.iface.removePluginMenu('Plugin', self.startButton)
def maskeAufrufen (self):
# add DockWidget to GUI
self.iface.addDockWidget(QtCore.Qt.RightDockWidgetArea, widget)
widget.setAllowedAreas(QtCore.Qt.RightDockWidgetArea)
# set first window as content of the DockWidget
self.gui = MainWindow(self)
widget.setWidget(self.gui)
class MainWindow(BASE, WIDGET):
def __init__(self, parent=None):
super(MainWindow, self).__init__()
self.setupUi(self)
self.window_second.clicked.connect(self.next_window)
def next_window(self):
# set second window as content of the DockWidget
window_the_second=Second_window()
widget.setWidget(window_the_second)
class Second_window(BASE2, WIDGET2):
def __init__(self):
super(Second_window, self).__init__()
self.setupUi(self)
I am new to Qt and PyQt and I appreciate it if someone can help me with this. I am trying to add a leaflet map to a GUI that I am creating using Qt designer and Python. Since there is no such widget, I create a simple Widget in the Qt Designer and promote it to a "LeafWidget" as shown below:
I save this file as (user_interface.ui) and then in my index.py file (under the same folder), I use the class leafWidget (with the same name as what defined in the Qt Designer) to define this new widget. I'm not sure if it is right or not. My "index.py" file that I run is as below.
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from pyqtlet import L, MapWidget
from PyQt5.uic import loadUiType
ui,_=loadUiType('user_interface.ui')
class LeafWidget (QWidget):
def __init__(self):
QWidget.__init__(self)
self.mapWidget = MapWidget()
self.map = L.map(self.mapWidget)
self.map.setView([39.764075, -86.159019], 10)
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png').addTo(self.map)
self.layout = QVBoxLayout(self)
self.layout.addWidget(self.mapWidget)
self.show()
class MainApp(QMainWindow, ui):
def __init__(self):
QMainWindow.__init__(self)
self.setupUi(self)
self.mainWindow_tabWidget.setCurrentIndex(1)
def main():
app=QApplication(sys.argv)
window = MainApp()
window.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
When I run it, it does open up the window, but the place for the map widget is empty as you see below. Am I defining this class correctly? In my MainApp class, do I need to add this new custom widget somehow? I don't get any specific errors in my debug console, So I'm not sure what I am missing.
I am new to Python and to PyQt. I have designed GUIs in MATLAB so its been a frustrating new experience. Right now, I have a main window and I want to open another login window on button push. What I have not decided is whether it should return the value of login to the parent window or another window. But either way I need to be able to open the login window through the pushbutton. I have created 2 files declaring the GUI one as a mainwindow and another as Dialog (does not seem like it is inheriting from QDialog though). The other 2 py files are classed calling the UIs separately and work fine. Each have their functions. I am pasting the main.py (mainwindow init and onOpen function code) along with logindialog.py init function code. Kindly help or else I will have to go back to Matlab where I can do this quite easily.`
import sys
from PyQt5 import QtWidgets, QtGui
from LoginDialog import LoginDialog
import UI_MSLDB_Main
from UI_LoginDialog import Ui_LoginDialog
#import Helper
#import Auth
#import TestFeature01
class Main(QtWidgets.QMainWindow, UI_MSLDB_Main.Ui_MSLDatabase):
def _init_(self, parent = None):
QtWidgets.QMainWindow._init_(self)
self.setupUi(self)
self.child = LoginDialog(self)
self.child.setupUi(QtWidgets.QDialog())
# self.createConnections()
self.pushButton_OpenPrimarylist.clicked.connect(self.onOpen)
def onOpen(self):
# window = QtWidgets.QDialog
# self.child = LoginDialog(window, Ui_LoginDialog)
# self.child.show()
# exec('LoginDialog.py')
self.child.show
# self.actionStudy.triggered.connect()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
# LoginDialog(QDialog, Ui_LoginDialog)
# loginDialog = LoginDialog(QDialog, UI_LoginDialog)
# username = loginDialog.username
# password =loginDialog.password
# Helper.dbConnect(username,password)
# isAuth = False
# result = -1
# while not isAuth:
# result = loginDialog.exec()
# if result == LoginDialog.Success or result == LoginDialog.Rejected:
# isAuth = True
# else:
# isAuth = False
result = 1
if result == 1:#LoginDialog.Success:
MSLDatabase = QtWidgets.QMainWindow()
ui = UI_MSLDB_Main.Ui_MSLDatabase()
ui.setupUi(MSLDatabase)
MSLDatabase.show()
# w.show()
app.exec_()
sys.exit(app.exec_())
There were multiple things I tried not knowing which would work. The commented codes are the ones I have tried and failed. LoginDialog class is below.
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QDialog
from PyQt5.QtWidgets import QMessageBox
import Auth
import Helper
from UI_LoginDialog import Ui_LoginDialog
class LoginDialog(QDialog, Ui_LoginDialog):
Success, Failed, Rejected, username, password = range(0,5)
def _init_(self):
QDialog._init_(self)
self.setupUi(self)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL
(_fromUtf8("accepted()")),self.onAccept)
QtCore.QObject.connect(self.buttonBox,
QtCore.SIGNAL(_fromUtf8("rejected()")),
self.onReject)
I am trying to show the loop data in Lineedit but it is not updating. Even the print command does not print the data on the terminal till I press any key other than return in lineedit. Have a look at the program and suggest me the changes:
import sys
import time
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class MyFrame(QWidget):
def __init__(self):
QWidget.__init__(self)
self.le = QLineEdit(self)
self.le.setGeometry(200,200,75,35)
i=0
self.le.setText(str(i))
self.connect(self.le, SIGNAL("textChanged(QString)"),self.updatedvalue)
def updatedvalue(self):
for i in range(1,5):
self.le.setText(str(i))
print(i)
time.sleep(1)
app=QApplication(sys.argv)
f=MyFrame()
f.show()
app.exec_()
You'll need to call QApplication.instance.processEvents() after updating your QLineEdit's text to force an update, otherwise you won't see anything until the final number.
You also need to change your textChanged() signal to textEdited(). Using textChanged() your updatedvalue() function will be called again on the first pass of your loop once setText() is called because you're updating the QLineEdit's text. The textEdited() signal won't be triggered if you update the text programmatically.
import sys
import time
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class MyFrame(QWidget):
def __init__(self):
QWidget.__init__(self)
self.le = QLineEdit(self)
self.le.setGeometry(200,200,75,35)
i = 0
self.le.setText(str(i))
self.connect(self.le, SIGNAL("textEdited(QString)"),self.updatedvalue)
def updatedvalue(self):
for i in range(1,5):
self.le.setText(str(i))
QApplication.instance().processEvents()
print(i)
time.sleep(1)
app=QApplication(sys.argv)
f=MyFrame()
f.show()
app.exec_()
As Bob mentioned, using a QTimer would be much better.