It is not a duplicate! I didn't want to make title really long, so it's short version may seem as a duplicate. The problem is a little bit bigger than in the title.
Environment: I'm trying to build painting app using PyQt5 and Qt-Designer. I've got three files in my project: main.py, slider.py, ui.py(UI from Qt-Designer generated by pyuic).
What do I need: I need to change App's brush size(self.variable) every time Slider value changes.
The problem itself: App Class inherits Ui_MainWindow Class from the file that I can't edit(it is generated every time). Ui_MainWindow sets Slider Class as its attribute. So basically Slider is App's attribute, and I need to change App's variable "canvas" while being in Slider Class.
I don't know how to access outer class variable in inner class method. Especially when I can't edit ui.py, so I could call Slider(self) instead of Slider(self.sidebar).
main.py
import sys
from PyQt5 import uic
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from ui import Ui_MainWindow
class App(QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
if __name__ == '__main__':
application = QApplication(sys.argv)
example = App()
example.show()
sys.exit(application.exec_())
slider.py
from PyQt5 import uic
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from functools import partial
import inspect
class Slider(QSlider):
def __init__(self, parent=None):
super().__init__(parent)
self.valueChanged.connect(self.valueChange)
self.setMinimum(8)
self.setMaximum(64)
self.setTickInterval(8)
def valueChange(self):
pass
# Here I need to change App.canvas, have no idea how to do it
ui.py
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'main.ui'
#
# Created by: PyQt5 UI code generator 5.11.3
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(912, 715)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.centralwidget)
self.horizontalLayout.setObjectName("horizontalLayout")
self.sidebar = QtWidgets.QWidget(self.centralwidget)
self.sidebar.setMinimumSize(QtCore.QSize(388, 0))
self.sidebar.setAutoFillBackground(True)
self.sidebar.setObjectName("sidebar")
self.clearButton = QtWidgets.QPushButton(self.sidebar)
self.clearButton.setGeometry(QtCore.QRect(20, 30, 91, 41))
self.clearButton.setObjectName("clearButton")
# This is where Slider is called
# The file is generated so I can't edit it
self.brushSizeSlider = Slider(self.sidebar)
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
self.brushSizeSlider.setGeometry(QtCore.QRect(20, 120, 160, 22))
self.brushSizeSlider.setOrientation(QtCore.Qt.Horizontal)
self.brushSizeSlider.setObjectName("brushSizeSlider")
self.brushSizeLabel = QtWidgets.QLabel(self.sidebar)
self.brushSizeLabel.setGeometry(QtCore.QRect(20, 90, 101, 16))
self.brushSizeLabel.setObjectName("brushSizeLabel")
self.brushColorDial = QtWidgets.QDial(self.sidebar)
self.brushColorDial.setGeometry(QtCore.QRect(20, 180, 50, 64))
self.brushColorDial.setObjectName("brushColorDial")
self.brushColorLabel = QtWidgets.QLabel(self.sidebar)
self.brushColorLabel.setGeometry(QtCore.QRect(20, 160, 101, 16))
self.brushColorLabel.setObjectName("brushColorLabel")
self.horizontalLayout.addWidget(self.sidebar)
self.canvas = Canvas(self.centralwidget)
self.canvas.setMinimumSize(QtCore.QSize(500, 500))
self.canvas.setMaximumSize(QtCore.QSize(5000, 5000))
self.canvas.setBaseSize(QtCore.QSize(500, 500))
self.canvas.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
self.canvas.setAutoFillBackground(True)
self.canvas.setStyleSheet("canvas{background-color: rgb(70, 70, 50);}")
self.canvas.setObjectName("canvas")
self.horizontalLayout.addWidget(self.canvas)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.clearButton.setText(_translate("MainWindow", "Clear canvas"))
self.brushSizeLabel.setText(_translate("MainWindow", "Current brush size:"))
self.brushColorLabel.setText(_translate("MainWindow", "Current brush color:"))
from canvas import Canvas
from slider import Slider
Related
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'PyosUI.ui'
#
# Created by: PyQt5 UI code generator 5.15.7
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import (
QApplication,
QLabel,
QMainWindow,
QPushButton,
QVBoxLayout,
QWidget
)
class GameWindow(QWidget):
def __init__(self):
super.__init__()
layout = QVBoxLayout()
self.label = QLabel("Hello!")
layout.addWidget(self.label)
self.setLayout(layout)
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.setEnabled(True)
Dialog.resize(1044, 601)
self.Notepad = QtWidgets.QPushButton(Dialog)
self.Notepad.setGeometry(QtCore.QRect(50, 520, 281, 61))
self.Notepad.setObjectName("Notepad")
self.Game = QtWidgets.QPushButton(Dialog)
self.Game.setGeometry(QtCore.QRect(390, 520, 271, 61))
self.Game.setObjectName("Game")
self.Poweroff = QtWidgets.QPushButton(Dialog)
self.Poweroff.setGeometry(QtCore.QRect(690, 520, 111, 31))
self.Poweroff.setObjectName("Poweroff")
self.Settings = QtWidgets.QPushButton(Dialog)
self.Settings.setGeometry(QtCore.QRect(690, 560, 111, 31))
self.Settings.setObjectName("Settings")
self.Date_time = QtWidgets.QDateTimeEdit(Dialog)
self.Date_time.setGeometry(QtCore.QRect(840, 20, 194, 22))
self.Date_time.setObjectName("Date_time")
self.label = QtWidgets.QLabel(Dialog)
self.label.setGeometry(QtCore.QRect(0, -20, 1051, 641))
self.label.setText("")
self.label.setPixmap(QtGui.QPixmap("background.png"))
self.label.setObjectName("label")
self.label.raise_()
self.Notepad.raise_()
self.Game.raise_()
self.Poweroff.raise_()
self.Settings.raise_()
self.Date_time.raise_()
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
l = QVBoxLayout()
self.Game.clicked.connect(self.button_clicked)
l.addWidget(self.Game)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "PyOS"))
self.Notepad.setText(_translate("Dialog", "Notepad"))
self.Game.setText(_translate("Dialog", "Game"))
self.Poweroff.setText(_translate("Dialog", "Poweroff"))
self.Settings.setText(_translate("Dialog", "Settings"))
def game_window(self):
game_window = QtWidgets.QDialog()
game_window.setWindowTitle("Game")
game_window.resize(600, 600)
game_window.show()
def button_clicked(self):
self.game_window()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Dialog = QtWidgets.QDialog()
ui = Ui_Dialog()
ui.setupUi(Dialog)
Dialog.show()
sys.exit(app.exec_())
The above code is the UI I made with Pyqt5 designer. For the work I want to make, when the 'Game' button is clicked, a window dedicated to the 'Game' button should appear.
However, when I run the code above, when I press the 'Game' button, a 600 x 600 window appears and then disappears.
Why?
How else can I solve this problem?
Thank you.
The game_window is a local variable within the game_window() method in Ui_Dialog.
Set the window as an instance and it should be fine.
Modified method
# other code remains same.
def game_window(self):
self._game_window = QtWidgets.QDialog()
self._game_window.setWindowTitle("Game")
self._game_window.resize(600, 600)
self._game_window.show()
Edit: The reason to add the underscore (_) is to avoid having the same name as the method name.
I have a log I have created with a simple [Add] text near each line which I want to be able to press and have it run a function that will know which line/text it has in this line.
I can also use QTextBrowser if needed for this.
My code:
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(401, 308)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.chat_log = QtWidgets.QTextEdit(self.centralwidget)
self.chat_log.setGeometry(QtCore.QRect(10, 10, 381, 241))
self.chat_log.setReadOnly(True)
self.chat_log.setObjectName("chat_log")
MainWindow.setCentralWidget(self.centralwidget)
class MainFrame(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(MainFrame, self).__init__(parent)
self.setupUi(self)
def appending(self):
self.chat_log.append("Somethingsomething [Add]")
self.chat_log.append("Hello[Add]")
self.chat_log.append("What is up [Add]")
self.chat_log.append("Big boy [Add]")
if __name__ == "__main__":
app = QApplication(sys.argv)
form = MainFrame()
form.show()
form.appending()
app.exec_()
What I want is basically when someone pressed "[Add]" it will know which line it pressed and will print the text in that line
Say I pressed the first line it will then print("Somethingsomething")
You need to make your [Add] texts clickable, the easiest way to do so is using HTML markup, then you just need to identify the text you had been clicking on:
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys
class MyTextEdit(QtWidgets.QTextEdit):
def mousePressEvent(self, e):
self.link = self.anchorAt(e.pos())
def mouseReleaseEvent(self, e):
if self.link:
print(f"Clicked on {self.link}")
self.link = None
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(401, 308)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.chat_log = MyTextEdit(self.centralwidget)
self.chat_log.setGeometry(QtCore.QRect(10, 10, 381, 241))
self.chat_log.setReadOnly(True)
self.chat_log.setObjectName("chat_log")
MainWindow.setCentralWidget(self.centralwidget)
class MainFrame(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(MainFrame, self).__init__(parent)
self.setupUi(self)
def appending(self):
messages = ["Somethingsomething", "Hello", "What is up", "Big bo"]
for msg in messages:
self.chat_log.append(
f'<span>{msg}<a style="color: pink" href="{msg}">[Add]</a></span>'
)
if __name__ == "__main__":
app = QApplication(sys.argv)
form = MainFrame()
form.show()
form.appending()
app.exec_()
Out:
Clicked on Big bo
Clicked on Hello
Clicked on Somethingsomething
I am trying to add a second tab (containing a pie chart visualization) to my PyQt5 GUI, but I cannot figure out how to display it. This second tab is laid out in a separate class and my program has the following structure:
main.py
from PyQt5 import QtWidgets, QtCore
from gui import UiMainWindow
import sys
class Logic(QtWidgets.QMainWindow, UiMainWindow,):
def __init__(self):
super().__init__()
self.setupUi(self)
self.treeView = QtWidgets.QTreeView(self.tabwidget.main_tab)
self.treeView.setGeometry(QtCore.QRect(270, 90, 801, 571))
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
logic = Logic()
logic.show()
sys.exit(app.exec_())
gui.py
from PyQt5 import QtWidgets, QtCore
from main_tab import MainTab
class UiMainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("Invoice Manager")
MainWindow.resize(1120, 750)
MainWindow.setTabShape(QtWidgets.QTabWidget.Rounded)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.tabwidget = MainTab(self.centralwidget)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
self.tabwidget.setCurrentIndex(0)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("Test", "Test"))
self.tabwidget.setTabText(
self.tabwidget.indexOf(self.tabwidget.main_tab),
_translate("MainWindow", "Main"))
self.tabwidget.setTabText(
self.tabwidget.indexOf(self.tabwidget.visual_tab),
_translate("MainWindow", "Tab_2"))
main_tab.py
from PyQt5 import QtCore, QtWidgets
from tab_2 import Tab2
class MainTab(QtWidgets.QTabWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setGeometry(QtCore.QRect(0, 0, 1120, 750))
self.main_tab = QtWidgets.QWidget()
self.addTab(self.main_tab, "")
self.visual_tab = Tab2()
self.addTab(self.visual_tab, "")
tab_2.py
from PyQt5 import QtWidgets
from PyQt5.QtChart import QChart, QChartView, QPieSeries, QPieSlice
from PyQt5.QtGui import QPainter, QPen
from PyQt5.QtCore import Qt
class Tab2(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.layout = QtWidgets.QVBoxLayout()
self.setLayout(self.layout)
self.create_piechart()
def create_piechart(self):
series = QPieSeries()
series.append("Label 1", 2)
series.append("Label 2", 2)
series.append("Label 3", 2)
pie_slice = QPieSlice()
pie_slice.setExploded(True)
pie_slice.setLabelVisible(True)
pie_slice.setPen(QPen(Qt.darkGreen, 2))
pie_slice.setBrush(Qt.green)
chart = QChart()
chart.legend().hide()
chart.addSeries(series)
chart.createDefaultAxes()
chart.setAnimationOptions(QChart.SeriesAnimations)
chart.setTitle("Pie Chart Example")
chart.legend().setVisible(True)
chart.legend().setAlignment(Qt.AlignBottom)
chartview = QChartView(chart)
chartview.setRenderHint(QPainter.Antialiasing)
I have been trying various solutions, but no luck so far. Any help would be highly appreciated!
I'm trying to make a puzzle game. My thought came from the 8-puzzle problem, so now I try to use the pyqt5. My opinion is that I choose a picture from my computer and then I try to use it. But when I try to upset the picture ,it comes some trouble.So I come here and look for help
since it comes to trouble so I simplify the code that just make the picture change into pieces. And now I just try them list on the qgraphicscene firstly, but I don't known why all of them stacked in the upper left corner, I just want them list in order which looks like the original picture, what should I do?
import sys
from vision import Ui_MainWindow
from PyQt5.QtWidgets import QMainWindow, QFileDialog
from PyQt5 import QtWidgets, QtGui, QtCore
from PIL import Image
class MyWindow(QMainWindow, Ui_MainWindow):
def __init__(self):
super(MyWindow, self).__init__()
self.setupUi(self)
self.item = []
self.if_opened = 0
self.dim = 3
self.upset.clicked.connect(self.make_upset)
def make_upset(self):
if self.image is None:
return
self.scene.clear()
self.showView.setScene(self.scene)
pixmap = QtGui.QPixmap(self.image)
x_side = self.image_file.size[0] / self.dim
y_side = self.image_file.size[1] / self.dim
count = 0
self.item.clear()
for j in range(self.dim):
for i in range(self.dim):
m = pixmap.copy(i * x_side, j * y_side, x_side, y_side)
self.item.append(QtWidgets.QGraphicsPixmapItem(m))
self.scene.addItem(self.item[count])
count = count + 1
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
myShow = MyWindow()
myShow.show()
sys.exit(app.exec_())
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1077, 741)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.upset = QtWidgets.QPushButton(self.centralwidget)
self.upset.setGeometry(QtCore.QRect(800, 210, 171, 51))
self.upset.setObjectName("upset")
self.showView = QtWidgets.QGraphicsView(self.centralwidget)
self.showView.setGeometry(QtCore.QRect(55, 38, 643, 623))
self.showView.setObjectName("showView")
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.upset.setText(_translate("MainWindow", "upset"))
I want to write a simple program shows a picture and print which pixel was clicked by override mousePressEvent of QGraphicsView.
When I don't override mousePressEvent of QGraphicsView, the image shows fine. But when I do override it, not only the position failed to show itself, the canvas become blank.
before override:
import sys
from PyQt5 import Qt
from PyQt5 import uic
a = Qt.QApplication(sys.argv)
from untitled import Ui_Form
# class override_graphicsView (Qt.QGraphicsView):
#
# def mousePressEvent(self, event):
# print(event.pos())
class Image_Process(Qt.QWidget):
def __init__(self):
super(Image_Process, self).__init__()
self.path = r"d:\test\winxp.jpg" #image path
self.new = Ui_Form()
self.new.setupUi(self)
# self.new.graphicsView = override_graphicsView()
self.pixmap = Qt.QPixmap()
self.pixmap.load(self.path)
self.pixmap = self.pixmap.scaled(self.size(), Qt.Qt.KeepAspectRatio)
self.graphicsPixmapItem = Qt.QGraphicsPixmapItem(self.pixmap)
self.graphicsScene = Qt.QGraphicsScene()
self.graphicsScene.addItem(self.graphicsPixmapItem)
self.new.graphicsView.setScene(self.graphicsScene)
my_Qt_Program = Image_Process()
my_Qt_Program.show()
sys.exit(a.exec_())
After I uncomment those lines, the canvas becomes this, and nothing was printed after click.
The untitled.py was generated from QtDesigner
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'untitled.ui'
#
# Created: Mon Jan 12 02:07:05 2015
# by: PyQt5 UI code generator 5.3.2
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(451, 286)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(Form.sizePolicy().hasHeightForWidth())
Form.setSizePolicy(sizePolicy)
self.gridLayout = QtWidgets.QGridLayout(Form)
self.gridLayout.setObjectName("gridLayout")
self.graphicsView = QtWidgets.QGraphicsView(Form)
self.graphicsView.setObjectName("graphicsView")
self.gridLayout.addWidget(self.graphicsView, 0, 0, 1, 1)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
Helped by Plouff, I have solved my own problem.
First, I should override QGraphicsScene instead of QGraphicsView, and the following line should be called for QGraphicsScene to handle mousePressEvent
super(override_graphicsScene, self).mousePressEvent(event)
Modified code:
import sys
from PyQt5 import Qt
from PyQt5 import uic
a = Qt.QApplication(sys.argv)
from untitled import Ui_Form
# Override like this:
class override_graphicsScene (Qt.QGraphicsScene):
def __init__(self,parent = None):
super(override_graphicsScene,self).__init__(parent)
def mousePressEvent(self, event):
super(override_graphicsScene, self).mousePressEvent(event)
print(event.pos())
class Image_Process(Qt.QWidget):
def __init__(self):
super(Image_Process, self).__init__()
self.path = r"d:\test\winxp.jpg" #image path
self.new = Ui_Form()
self.new.setupUi(self)
self.pixmap = Qt.QPixmap()
self.pixmap.load(self.path)
self.pixmap = self.pixmap.scaled(self.size(), Qt.Qt.KeepAspectRatio)
self.graphicsPixmapItem = Qt.QGraphicsPixmapItem(self.pixmap)
self.graphicsScene = override_graphicsScene(self)
self.graphicsScene.addItem(self.graphicsPixmapItem)
self.new.graphicsView.setScene(self.graphicsScene)
my_Qt_Program = Image_Process()
my_Qt_Program.show()
sys.exit(a.exec_())
The program works fine.