I have a PyQT layout built with QWidget. I have a few labels, buttons, etc and now I want to add a image that changes color on click. For this, I have built a class as opposed to using a default widget. For the default widgets I am easily able to add them back into the main window but I am not sure how to do this with the custom class.
This is how my code is laid out:
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.setWindowTitle("Project Starfish Prototype GUI")
MainWindow.resize(1920, 1080)
MainWindow.setStyleSheet("background-color: rgb(9, 40, 122);")
self.cameraViewer = QtWidgets.QWidget(MainWindow)
self.cameraViewer.setObjectName("cameraViewer")
self.logo = QtWidgets.QLabel(self.cameraViewer)
self.logo.setGeometry(QtCore.QRect(825, 20, 270, 42))
pixmap = QPixmap('teleflex-logo.png')
pixmap = pixmap.scaled(270, 42)
self.logo.setPixmap(pixmap)
self.cameraFeed = QtWidgets.QLabel(self.cameraViewer)
self.cameraFeed.setGeometry(QtCore.QRect(320, 110, 1280, 960))
self.cameraFeed.setObjectName("cameraFeed")
self.startBTN = QtWidgets.QPushButton(self.cameraViewer)
self.startBTN.setGeometry(QtCore.QRect(110, 610, 100, 100))
self.startBTN.setObjectName("startBTN")
self.startBTN.clicked.connect(self.StartFeed)
There is some more code but this is the jist. I add the default QButton or QLabel to the main QWidget.
Now I am trying to add my Class to the main window but I am not sure how to do this.
Here is my code for adding the Class (inside setupUI) to the main window and then my class:
self.imageButton = PicButton(QPixmap("image.png"))
self.imageButton = self.imageButton(self.cameraViewer)
self.imageButton.setGeometry(QtCore.QRect(110, 110, 100, 100))
self.imageButton.setObjectName("imageButton")
class PicButton(QAbstractButton):
def __init__(self, pixmap, parent=None):
super(PicButton, self).__init__(parent)
self.pixmap = pixmap
def hover(self):
def click(self):
I do understand that my code does not make sense, specifically this line self.imageButton = self.imageButton(self.cameraViewer) but I am not sure what the solution is.
Related
My question is simple, I am trying to open a child window within the main window. I took help of all of the answers so this question is not a duplicate. My child window comes for some time and then disappears automatically.
import random
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5 import QtWidgets, uic
class SubWindow(QWidget):
def __init__(self, parent = None):
super(SubWindow, self).__init__(parent)
label = QLabel("Sub Window", self)
label.setGeometry(0, 0, 20, 10)
self.show()
class pro(QWidget):
def __init__(self, parent=None):
super(pro, self).__init__(parent)
self.acceptDrops()
self.x = 200
self.y = 200
self.width = 800
self.length = 800
self.setGeometry(self.x, self.y, self.width, self.length)
self.setWindowTitle("PA")
label = QLabel(self)
pixmap = QPixmap('p_bg.png')
label.setPixmap(pixmap)
label.setGeometry(0, 0, 1100, 1000)
self.initgui()
def register_system(self):
opener = SubWindow()
opener.show()
def initgui(self):
self.btn_log = QPushButton(self)
self.btn_log.setGeometry(440, 250, 150, 30)
self.btn_log.setText(" Login ")
self.btn_log.adjustSize()
self.btn_sign = QPushButton(self)
self.btn_sign.setGeometry(440, 300, 150, 30)
self.btn_sign.setText(" Register ")
self.btn_sign.adjustSize()
self.btn_sign.clicked.connect(self.register_system)
self.welcome = QLabel("Arial font", self)
self.welcome.setText("Welcome")
self.welcome.setGeometry(410, 100, 200, 30)
self.welcome.setStyleSheet("background-color:transparent;")
self.welcome.setFont(QFont("Arial", 30))
self.show()
def window():
apk = QApplication(sys.argv)
win = pro()
win.show()
sys.exit(apk.exec_())
window()
I took help to make a child window from here:https://www.codersarts.com/post/multiple-windows-in-pyqt5-codersarts , I used type 2 resource in my case.
The reason probably is that the variable opener has scope within the register_system method only; it is getting deleted after the method exits, you can modify the code either to create the variable as an attribute to the class object using self and then show the widget like this:
def register_system(self):
self.opener = SubWindow()
self.opener.show()
Or, you can just create a variable opener at global scope, then use the global variable to assign and show the widget:
# imports
opener = None
class SubWindow(QWidget):
def __init__(self, parent = None):
#Rest of the code
class pro(QWidget):
def __init__(self, parent=None):
# Rest of the code
def register_system(self):
global opener
opener = SubWindow()
opener.show()
# Rest of the code
On a side note, you should always use layout for the widgets in PyQt application, you can take a look at Layout Management
Why my program is closing when I am using Slider in pyqt5? It starts normal but after using Slider it close. I have to change size of circle in first window by using Slider from second window. This is my full code, beacuse I don't know what could be wrong.
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QPainter, QBrush, QPen
from PyQt5.QtCore import Qt
import sys
class ThirdWindow(QWidget):
def __init__(self):
super().__init__()
hbox = QHBoxLayout()
sld = QSlider(Qt.Horizontal, self)
sld.setRange(0, 100)
sld.setFocusPolicy(Qt.NoFocus)
sld.setPageStep(5)
sld.valueChanged.connect(self.updateLabel)
self.label = QLabel('0', self)
self.label.setAlignment(Qt.AlignCenter | Qt.AlignVCenter)
self.label.setMinimumWidth(80)
hbox.addWidget(sld)
hbox.addSpacing(15)
hbox.addWidget(self.label)
self.setLayout(hbox)
self.setGeometry(600, 60, 500, 500)
self.setWindowTitle('QSlider')
self.show()
def updateLabel(self, value):
self.label.setText(str(value))
self.parentWidget().radius = value
self.parentWidget().repaint()
class Window(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.setWindowTitle("Dialogi")
self.w = ThirdWindow()
actionFile = self.menuBar().addMenu("Dialog")
action = actionFile.addAction("Zmień tło")
action1 = actionFile.addAction("Zmień grubość koła")
action1.triggered.connect(self.w.show)
self.setGeometry(100, 60, 300, 300)
self.setStyleSheet("background-color: Green")
self.radius = 100 # add a variable radius to keep track of the circle radius
def paintEvent(self, event):
painter = QPainter(self)
painter.setPen(QPen(Qt.gray, 8, Qt.SolidLine))
# change function to include radius
painter.drawEllipse(100, 100, self.radius, self.radius)
app = QApplication(sys.argv)
screen = Window()
screen.show()
sys.exit(app.exec_())
parentWidget allows access to a widget declared as parent for Qt.
Creating an object using self.w = ... doesn't make that object a child of the parent (self), you are only creating a reference (w) to it.
If you run your program in a terminal/prompt you'll clearly see the following traceback:
Exception "unhandled AttributeError"
'NoneType' object has no attribute 'radius'
The NoneType refers to the result of parentWidget(), and since no parent has been actually set, it returns None.
While you could use parentWidget if you correctly set the parent for that widget (by adding the parent to the widget constructor, or using setParent()), considering the structure of your program it wouldn't be a good choice, and it's usually better to avoid changes to a "parent" object directly from the "child": the signal/slot mechanism of Qt is exactly intended for the modularity of Object Oriented Programming, as a child should not really "care" about its parent.
The solution is to connect to the slider from the "parent", and update it from there.
class ThirdWindow(QWidget):
def __init__(self):
# ...
# make the slider an *instance member*, so that we can easily access it
# from outside
self.slider = QSlider(Qt.Horizontal, self)
# ...
class Window(QMainWindow):
def __init__(self):
# ...
self.w.slider.valueChanged.connect(self.updateLabel)
def updateLabel(self, value):
self.radius = value
self.update()
You obviously need to remove the valueChanged connection in the ThirdWindow class, as you don't need it anymore.
Also note that you rarely need repaint(), and update() should be preferred instead.
I need to add info of students (it looks like a table) to the window. It's done in a function called "addStudentStats" and it's added to a main widget. I was trying to make another widget insert scrollbar, and this widget insert into a main one. But it didn't work. Then i tried to make the whole window scrollable, but i couldn't do it either. If anyone can can write those few lines of code (i think there are few, but don't know which) i would be pleased.
Read here
I've added a scrollbar to my window. The program fills it with data, which goes down the screen, but i cannot scroll
from PyQt5.QtWidgets import QPushButton, QWidget, QLabel,QScrollArea, QApplication, QMainWindow
from PyQt5.QtCore import Qt
import sys
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.uiMain = UIMainTeacher()
self.setUpUI(self)
def setUpUI(self, MainWindow):
MainWindow.setGeometry(50, 50, 400, 450)
MainWindow.setFixedSize(1800, 1000)
MainWindow.setWindowTitle("Login")
self.uiMain = UIMainTeacher()
self.gotoTeacher()
def gotoTeacher(self):
self.uiMain.setupUI(self, type)
self.show()
class UIMainTeacher(object):
def setupUI(self, MainWindow, userId):
MainWindow.setGeometry(50, 50, 400, 450)
MainWindow.setFixedSize(1800, 1000)
MainWindow.setWindowTitle("Main")
self.mainWindow = MainWindow
self.centralwid = QScrollArea(MainWindow)
self.centralwid.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
self.centralwidget = QWidget(self.centralwid)
self.exitButton = QPushButton("Exit", self.centralwid)
self.exitButton.move(1700, 0)
self.CourseLabel = QLabel("No Kourse yet", self.centralwid)
self.CourseLabel.move(900, 20)
self.AddCourseButton = QPushButton('Add Course', self.centralwid)
self.AddCourseButton.move(1700, 25)
self.CourseLabel = QLabel("Course", self.centralwidget)
self.CourseLabel.move(900, 20)
self.AddStudentsButton = QPushButton("Add Students", self.centralwid)
self.AddStudentsButton.move(1700, 100)
self.taskLabel = QLabel("TASKS:", self.centralwidget)
self.taskLabel.move(160, 20)
self.AddTaskButton = QPushButton('Add Task', self.centralwid)
self.AddTaskButton.move(1700, 50)
self.centralwid.setWidget(self.centralwidget)
MainWindow.setCentralWidget(self.centralwid)
x, y = 600, 0
for _ in range(200):
label = QLabel("Test Test", self.centralwid)
label.move(x, y)
y += 50
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MainWindow()
sys.exit(app.exec_())
The problem is simple QScrollArea is a container that serves to show another widget that has a large size, and that widget is what you pass through the setWidget() method. QScrollArea calculates the necessary size using the sizeHint() of the widget, so in your case the one that is caudding the problem is that widget since its sizeHint() is 0, 0. Why is it 0, 0? because it has nothing inside since the labels are children of the QScrollArea and not the widget, and even if it did not have the sizeHint() since there are at least 2 ways to calculate them: the layout gives you that information but in your case you use it, and the second is to set a fixed size to the widget, and that is the solution I have chosen, I do not know if it is what you want since I do not know what type of output you want, but you can see that the QScrollArea is visible.
class UIMainTeacher(object):
def setupUI(self, MainWindow):
MainWindow.setGeometry(50, 50, 400, 450)
MainWindow.setFixedSize(1800, 1000)
MainWindow.setWindowTitle("Main")
self.mainWindow = MainWindow
self.centralwid = QScrollArea(MainWindow)
self.centralwid.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
self.centralwidget = QWidget(self.centralwid)
self.exitButton = QPushButton("Exit", self.centralwid)
self.exitButton.move(1700, 0)
self.CourseLabel = QLabel("No Kourse yet", self.centralwid)
self.CourseLabel.move(900, 20)
self.AddCourseButton = QPushButton('Add Course', self.centralwid)
self.AddCourseButton.move(1700, 25)
self.CourseLabel = QLabel("Course", self.centralwidget)
self.CourseLabel.move(900, 20)
self.AddStudentsButton = QPushButton("Add Students", self.centralwid)
self.AddStudentsButton.move(1700, 100)
self.taskLabel = QLabel("TASKS:", self.centralwidget)
self.taskLabel.move(160, 20)
self.AddTaskButton = QPushButton('Add Task', self.centralwid)
self.AddTaskButton.move(1700, 50)
self.centralwid.setWidget(self.centralwidget)
MainWindow.setCentralWidget(self.centralwid)
x, y = 600, 0
for _ in range(200):
label = QLabel("Test Test", self.centralwidget)
label.move(x, y)
y += 50
self.centralwidget.setFixedWidth(800)
self.centralwidget.setFixedHeight(y)
so if you are going to add more elements you will have to calculate and set the setFixedHeight(), another option is to use layouts but since I do not know what design you expect I will not be able to provide you with that second solution.
I want to load an image If I click on a button but only a little tiny pixel of the image appears.
It looks like that:
class MyWindow(QWidget):
def __init__(self):
super().__init__()
self.resize(1000, 1000)
self.setWindowTitle("MyWindow")
self.setWindowIcon(QIcon("myIcon.ico"))
self.setMaximumSize(width, height)
self.setMinimumSize(1000, 1000)
self.canvas = QGroupBox(self)
self.canvas.setStyleSheet("QGroupBox { border: 1px solid #9F9B9B}")
self.canvas.move(350, 30)
self.canvas.resize(210, 220)
self.bImage = QPushButton("Load Image", self)
self.bImage.move(150, 207)
self.bImage.clicked.connect(self.openImage)
self.show()
def openImage(self):
self.label = QLabel(self)
self.preview = QPixmap("image.png")
self.label.setPixmap(self.preview)
self.label.move(350, 30)
But Strangely if I place the code from the openImage() function into the first lines of the init() funtion the image will be completely displayed.
What shall I do to load the entire image by the openImage() function?
It is generally a bad idea to try to position widgets using absolute values. You should always use layouts whenever possible. The reason why the image doesn't show is because you move the label to a position behind the group-box. Instead, you should put the label in a layout inside the group-box:
class MyWindow(QtGui.QWidget):
def __init__(self):
...
self.canvas = QtGui.QGroupBox(self)
...
self.label = QtGui.QLabel(self)
layout = QtGui.QVBoxLayout(self.canvas)
layout.addWidget(self.label)
...
def openImage(self):
self.preview = QtGui.QPixmap("image.png")
self.label.setPixmap(self.preview)
I`m new in PyQT4 and I've faced the problem below.
Some application must collect users' data on one screen
and show next screen on button click.
main.py
app = QtGui.QApplication(sys.argv)
#here I create main window with inherited class
w = SAN_MainWindow()
#and apply some basic geometry
w.SetUI()
#here first screen rendered and button event applyed
w.ApplyWidget( SAN_Intro() )
w.show()
sys.exit(app.exec_())
Rendering of first widget occurs correctly.
SAN_MainWindow.py:
class SAN_MainWindow(QtGui.QMainWindow):
def __init__(self ):
super(SAN_MainWindow, self).__init__()
def SetUI(self):
self.setObjectName(_fromUtf8("MainWindow"))
self.resize(789, 602)
self.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8))
self.central_widget = QtGui.QWidget(self)
self.central_widget.setObjectName(_fromUtf8("central_widget"))
self.setCentralWidget(self.central_widget)
def ApplyWidget( self, widget ):
self.active_widget = widget
self.active_widget.Setup(self.central_widget)
self.active_widget.SetControls( self )
def RemoveActiveWidget( self ):
self.active_widget.widget().setParent(None)
def ShowInstruction( self ):
self.RemoveActiveWidget()
self.ApplyWidget( SAN_Instruction() )
#self.centralWidget().update() <- Problem
SAN_Intro.py:
class SAN_Intro(object):
def __init__(self):
super(SAN_Intro, self).__init__()
def Setup(self, widget):
self.gridLayoutWidget = QtGui.QWidget(widget)
self.gridLayoutWidget.setGeometry(QtCore.QRect(80, 30, 638, 451))
self.gridLayoutWidget.setObjectName(_fromUtf8("gridLayoutWidget"))
self.gridLayout = QtGui.QGridLayout(self.gridLayoutWidget)
self.gridLayout.setContentsMargins(-1, 16, 16, -1)
self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
#a lot of form inputs instructions....
def SetControls( self, main_window ):
QtCore.QObject.connect(self.pushButton, QtCore.SIGNAL("clicked()"), main_window.ShowInstruction)
def widget(self):
return self.gridLayoutWidget
SAN_Instruction is almost the same as SAN_Intro, but with different commands in Setup:
class SAN_Instruction(object):
def __init__(self):
super(SAN_Instruction, self).__init__()
def Setup(self, widget):
self.verticalLayoutWidget = QtGui.QWidget(widget)
self.verticalLayoutWidget.setGeometry(QtCore.QRect(40, 20, 591, 521))
self.verticalLayoutWidget.setObjectName(_fromUtf8("verticalLayoutWidget"))
self.verticalLayout = QtGui.QVBoxLayout(self.verticalLayoutWidget)
self.verticalLayout.setMargin(0)
self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
#a lot of form inputs instructions....
def SetControls( self, main_window ):
pass
def widget(self):
return self.verticalLayoutWidget
AND HERE IS QUESTION:
How must I show the second (generated on fly with SAN_Instruction) widget?
I tried to update/show/repaint mainwindow/centralwidget/parent.
But all I've got on button click is self.RemoveActiveWidget().
Maybe my concept is incorrect?
Thanx in advance
Well, your code isn't complete but i would advise you to take advantage of the hide() method.
You can define this in your button function, so that all the widgets you do not want to appear get hidden, and on the same function call the widgets you want to appear on their place. I use to do that way because it makes my projects more organized and easy to track and debug. Furthermore, this also allows you to make that widgets visible again if you need, with the show() method.
You can use a "QtGui.QStackedWidget()". You Split your Window to many Frames, add each frame to the QStackedWidget() and use function setCurrentWidget() to choose which frame to display (switch between frames).
self.central_widget.addWidget(self.mainFrame)
self.central_widget.setCurrentWidget(self.mainFrame)