I try to display a SplashScreeen with a gif and a progressbar in it, while a method calculates.
Therefore I have one main.py with a PyQt5 MainWindow Application. In this application method starts, see my calc.py:
from time import sleep, time
import pandas as pd
import concurrent.futures, requests, queue, sys
from threading import Thread
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QIcon, QFont, QKeySequence, QPalette, QBrush, QColor, QPixmap, QMovie, QPainter
from PyQt5.QtCore import Qt, QSize, QRect, QThread, pyqtSignal, QTimer
class MovieSplashScreen(QSplashScreen):
def __init__(self, movie, parent = None):
movie.jumpToFrame(0)
pixmap = QPixmap(movie.frameRect().size())
QSplashScreen.__init__(self, pixmap)
self.movie = movie
self.movie.frameChanged.connect(self.repaint)
def showEvent(self, event):
self.movie.start()
def hideEvent(self, event):
self.movie.stop()
def paintEvent(self, event):
painter = QPainter(self)
pixmap = self.movie.currentPixmap()
self.setMask(pixmap.mask())
painter.drawPixmap(0, 0, pixmap)
def sizeHint(self):
return self.movie.scaledSize()
def splashScreen(zeit = 0):
print('===splashScreen(self)====')
dapp = QApplication(['a', 's'])
# Create and display the splash screen
movie = QMovie("img\\fuchs.gif")
if zeit <= 2:
gerundet = 50
elif zeit > 2:
gerundet = zeit * 60
print("gerundet = ", gerundet)
splash = MovieSplashScreen(movie)
width = splash.frameGeometry().width()
height = splash.frameGeometry().height()
x = splash.pos().x()
y = splash.pos().y()
print('splash x,y: ',width, height, x, y)
splash.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint)
splash.setEnabled(False)
# adding progress bar
palette = QPalette()
palette.setColor(QPalette.Highlight, Qt.green)
progressBar = QProgressBar()
progressBar.setMaximum(gerundet)
progressBar.setGeometry(x, y-30, width, 20)
progressBar.setPalette(palette)
progressBar.setWindowFlags(Qt.SplashScreen | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
gerundet = gerundet + 1
#splash.setMask(splash_pix.mask())
progressBar.show()
splash.show()
splash.showMessage("<h1><font color='red'></font></h1>", Qt.AlignTop | Qt.AlignCenter, Qt.black)
for i in range(1, gerundet):
progressBar.setValue(i)
t = time()
while time() < t + 0.1:
dapp.processEvents()
progressBar.hide()
window = QWidget()
splash.finish(window)
dapp.deleteLater() # here are troubles maybe in cause of main.py with the GUI has a app = QAplllication(sys.argv) too?
def getSignals(selectedCoins, selectedCoinsText):
print("=====getFilteredSignals====")
dfFilter = []
noResults = []
print("selectedCoins: ", selectedCoins)
zeit = len(selectedCoins)
# Problems here?
t = Thread(target=splashScreen, args=(zeit,))
t.start()
for i in range(len(selectedCoins)):
print("i: "+str(i)+" ", selectedCoins[i])
if i >= 1:
sleep(6)
result = makeSignals(selectedCoins[i])
print("results.empty: ", result.empty)
if result.empty == False:
result = result.set_index('Pair', inplace=False)
dfFilter.append(result)
else:
print("selectedCoinsText"+str(i)+": ", selectedCoinsText[i])
noResults.append(selectedCoinsText[i])
print("\nlen(dfFilter): ", len(dfFilter))
if len(dfFilter) == 0:
print("\n\n====in if len(dfFilter) == 0: \n dfFilter: ", dfFilter)
# Creating an empty Dataframe with column names only
dfempty = pd.DataFrame(columns=['User_ID', 'UserName', 'Action'])
print("Empty Dataframe ", dfempty,'\n dfempty.empty: ', dfempty.empty)
return dfempty
elif len(dfFilter) > 0:
for i in range(len(dfFilter)):
print("\n\n====in for loop=== \n dfFilter ["+str(i)+"]: \n", dfFilter[i])
filteredResults = pd.concat(dfFilter, axis=0, sort=False)
#filteredResults['Gain (%)'] = pd.to_numeric(filteredResults['Gain (%)'], errors='coerce')
filteredResults = filteredResults.sort_values(by='Gain (%)', ascending=False, inplace=False)
filteredResults = filteredResults.reset_index(inplace=False)
print('\nfilteredResults: \n', filteredResults, "\n", filteredResults.dtypes)
return filteredResults
self.results = calc.getSignals( a, aText)
Splashscreen and progressebar are displayed, but then the gui freezes and crashed.
So from main.py calc.py is started.
main.py is a gui with app = Qapplication() and a MainWindow().
Looks like:
import calc
class MainWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.font = QFont("Helvetica", 9)
self.setFont(self.font)
...
self.getSignals(a, aText)
...
def getSignals(self, a, aText):
zeit = len(a)
self.results = calc.getSignals(a, aText)
if __name__ == '__main__':
app = QApplication(sys.argv)
app.setStyle('Fusion')
mw = MainWindow()
mw.show()
sys.exit(app.exec_())
I try to use dapp.exit(exec_()) instead of dapp.deleteLater() in calc.py , but it still crashed too.
You are confusing concepts:
The time consuming task must be executed in another thread, in your case that task is processing.
If you want to control the GUI with the information obtained in the other thread then you must use signals, in this case I have created 2 signals that send the value of the QProgressBar showing the windows, and the other one sends the result.
If you want to do periodic tasks then use a QTimer.
With the above the solution is:
import os
import threading
import time
from PyQt5 import QtCore, QtGui, QtWidgets
import pandas as pd
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
class MovieSplashScreen(QtWidgets.QSplashScreen):
def __init__(self, movie, parent=None):
self._movie = movie
self.movie.jumpToFrame(0)
pixmap = QtGui.QPixmap(movie.frameRect().size())
super(MovieSplashScreen, self).__init__(pixmap)
self.setParent(parent)
self.movie.frameChanged.connect(self.repaint)
#property
def movie(self):
return self._movie
def showEvent(self, event):
self.movie.start()
super(MovieSplashScreen, self).showEvent(event)
def hideEvent(self, event):
self.movie.stop()
super(MovieSplashScreen, self).hideEvent(event)
def paintEvent(self, event):
painter = QtGui.QPainter(self)
pixmap = self.movie.currentPixmap()
self.setMask(pixmap.mask())
painter.drawPixmap(0, 0, pixmap)
def sizeHint(self):
return self.movie.scaledSize()
class Processor(QtCore.QObject):
started = QtCore.pyqtSignal(int)
filteredResultsSignal = QtCore.pyqtSignal(pd.DataFrame)
def execute(self, selectedCoins, selectedCoinsText):
threading.Thread(
target=self._execute, args=(selectedCoins, selectedCoinsText)
).start()
def _execute(self, selectedCoins, selectedCoinsText):
print("=====getFilteredSignals====")
dfFilter = []
noResults = []
print("selectedCoins: ", selectedCoins)
zeit = len(selectedCoins)
self.started.emit(zeit)
for i, (coin, text) in enumerate(zip(selectedCoins, selectedCoinsText)):
print("i: {} {}".format(i, coin))
if i >= 6:
time.sleep(6)
result = makeSignals(selectedCoins[i])
print("results.empty: ", result.empty)
if not result.empty:
result = result.set_index("Pair", inplace=False)
dfFilter.append(result)
else:
print("selectedCoinsText{}: {}".format(i, text))
noResults.append(text)
print("\nlen(dfFilter): ", len(dfFilter))
if len(dfFilter) == 0:
print("\n\n====in if len(dfFilter) == 0: \n dfFilter: ", dfFilter)
# Creating an empty Dataframe with column names only
filteredResults = pd.DataFrame(columns=["User_ID", "UserName", "Action"])
print(
"Empty Dataframe ",
filteredResults,
"\n dfempty.empty: ",
filteredResults.empty,
)
elif len(dfFilter) > 0:
for i, df_filter in enumerate(dfFilter):
print(
"\n\n====in for loop=== \n dfFilter [{}]: \n{}".format(i, df_filter)
)
filteredResults = pd.concat(dfFilter, axis=0, sort=False)
# filteredResults['Gain (%)'] = pd.to_numeric(filteredResults['Gain (%)'], errors='coerce')
filteredResults = filteredResults.sort_values(
by="Gain (%)", ascending=False, inplace=False
)
filteredResults = filteredResults.reset_index(inplace=False)
print(
"\nfilteredResults: \n", filteredResults, "\n", filteredResults.dtypes
)
self.filteredResultsSignal.emit(filteredResults)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
font = QtGui.QFont("Helvetica", 9)
self.setFont(font)
self.processor = Processor(self)
self.processor.started.connect(self.on_started)
self.processor.filteredResultsSignal.connect(self.on_filteredResultsSignal)
self.processor.execute("a", "aText")
movie_path = os.path.join(CURRENT_DIR, "img", "fuchs.gif")
movie = QtGui.QMovie(movie_path)
self.splash = MovieSplashScreen(movie)
self.splash.setWindowFlags(
QtCore.Qt.WindowStaysOnTopHint | QtCore.Qt.FramelessWindowHint
)
self.splash.setEnabled(False)
# adding progress bar
palette = QtGui.QPalette()
palette.setColor(QtGui.QPalette.Highlight, QtCore.Qt.green)
self.progressBar = QtWidgets.QProgressBar()
self.progressBar.setPalette(palette)
self.progressBar.setWindowFlags(
QtCore.Qt.SplashScreen
| QtCore.Qt.FramelessWindowHint
| QtCore.Qt.WindowStaysOnTopHint
)
self.progressBar.move(self.splash.pos() + QtCore.QPoint(0, -30))
self.progressBar.resize(self.splash.width(), 30)
self.counter = 0
self.gerundet = 0
self.timer = QtCore.QTimer(interval=100, timeout=self.on_timeout)
#QtCore.pyqtSlot(pd.DataFrame)
def on_filteredResultsSignal(self, df):
print(df)
#QtCore.pyqtSlot()
#QtCore.pyqtSlot(int)
def on_started(self, zeit=0):
gerundet = 50 if zeit <= 2 else zeit + 60
print("gerundet = ", gerundet)
gerundet = gerundet + 1
self.progressBar.setMaximum(gerundet)
# splash.setMask(splash_pix.mask())
self.progressBar.show()
self.splash.show()
self.splash.showMessage(
"<h1><font color='red'></font></h1>",
QtCore.Qt.AlignTop | QtCore.Qt.AlignCenter,
QtCore.Qt.black,
)
self.counter = 1
self.gerundet = gerundet
self.timer.start()
#QtCore.pyqtSlot()
def on_timeout(self):
self.progressBar.setValue(self.counter)
self.counter += 1
if self.counter > self.gerundet:
self.timer.stop()
self.progressBar.hide()
self.splash.close()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
app.setStyle("Fusion")
mw = MainWindow()
mw.show()
sys.exit(app.exec_())
Related
I'm trying to draw a line interactively but I can't figure out how to do it. Anyone can help me?
I'm using PyQt5. I create a QGraphicsScene, I override mouse press event but when I try to draw the draw the it draw nothing.
Finally, I have another question. How can I snap this line to the grid?
import math
import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class neGraphicScene(QGraphicsScene):
_colorBackGround: str
_colorLightLines: str
_colorDarkLines: str
_penLight: QPen
_penDark: QPen
gridSize: int = 20
gridSquares: int = 5
isLineDrawing = False
def __init__(self, parent=None):
QGraphicsScene.__init__(self, QRectF(-1000, -1000, 2000, 2000), parent)
self.setSceneColor()
self.begin, self.destination = QPoint(), QPoint()
def setSceneColor(self, _lightLines="#2f2f2f", _darkLines="#292929", _background="#393939"):
self._colorBackGround = _background
self._colorLightLines = _lightLines
self._colorDarkLines = _darkLines
self._penLight = QPen(QColor(self._colorLightLines))
self._penLight.setWidth(1)
self._penDark = QPen(QColor(self._colorDarkLines))
self._penDark.setWidth(2)
self.setBackgroundBrush(QColor(self._colorBackGround))
def setGraphicScene(self, width, height):
self.setSceneRect(-width // 2, -height // 2, width, height)
def mouseDoubleClickEvent(self, event):
QGraphicsScene.mouseMoveEvent(self, event)
def mousePressEvent(self, event):
self.isLineDrawing = True
if event.buttons() & Qt.LeftButton:
print('Point 1')
self.begin = event.pos()
self.destination = self.begin
self.update()
def mouseMoveEvent(self, event):
if event.buttons() & Qt.LeftButton:
print('Point 2')
self.destination = event.pos()
self.update()
def mouseReleaseEvent(self, event):
self.isLineDrawing = False
print('Point 3')
def drawBackground(self, painter, rect):
super(neGraphicScene, self).drawBackground(painter, rect)
# self.drawBackgroundGrid(painter, rect)
if self.isLineDrawing:
if not self.begin.isNull() and not self.destination.isNull():
line = QLineF(self.begin, self.destination)
painter.setPen(Qt.red)
painter.drawLine(line)
This is the QGraphicsView and the QWidgetStuff to made the minimal example working properly:
class neGraphicView(QGraphicsView):
def __init__(self, graphicScene, parent=None):
super().__init__(parent)
# self._dragPos = QPoint(0, 0)
self.sharedGraphicScene = graphicScene
self.setScene(self.sharedGraphicScene)
self._mousePressed = False
self._isPanning = False
self.initUI()
def initUI(self):
self.setRenderHints(
QPainter.Antialiasing | QPainter.HighQualityAntialiasing |
QPainter.TextAntialiasing | QPainter.SmoothPixmapTransform)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setDragMode(QGraphicsView.RubberBandDrag)
class NodeEditorWindow(QWidget):
mainLayout: QVBoxLayout
mainGraphicsScene: neGraphicScene
view: neGraphicView
def __init__(self, parent=None):
super(NodeEditorWindow, self).__init__(parent)
self.initUI()
def initUI(self):
self.setGeometry(200, 200, 800, 600)
self.mainLayout = QVBoxLayout()
self.mainLayout.setContentsMargins(0, 0, 0, 0)
self.setLayout(self.mainLayout)
self.mainGraphicsScene = neGraphicScene()
self.view = neGraphicView(self.mainGraphicsScene, self)
self.mainLayout.addWidget(self.view)
self.setWindowTitle("Node Editor")
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
app.setStyle("Fusion")
win = NodeEditorWindow()
win.show()
sys.exit(app.exec())
This is the grid function:
def drawBackgroundGrid(self, _painter, _rect):
# here we create our grid
_left = int(math.floor(_rect.left()))
_right = int(math.ceil(_rect.right()))
_top = int(math.floor(_rect.top()))
_bottom = int(math.ceil(_rect.bottom()))
first_left = _left - (_left % self.gridSize)
first_top = _top - (_top % self.gridSize)
try:
# compute all lines to be drawn
lightLines, darkLines = [], []
for x in range(first_left, _right, self.gridSize):
if x % (self.gridSize * self.gridSquares) != 0:
lightLines.append(QLineF(x, _top, x, _bottom))
else:
darkLines.append(QLineF(x, _top, x, _bottom))
for y in range(first_top, _bottom, self.gridSize):
if y % (self.gridSize * self.gridSquares) != 0:
lightLines.append(QLineF(_left, y, _right, y))
else:
darkLines.append(QLineF(_left, y, _right, y))
# draw the lines
_painter.setPen(self._penLight)
_painter.drawLines(*lightLines)
_painter.setPen(self._penDark)
_painter.drawLines(*darkLines)
except Exception as e:
# print(e)
pass
I would like to use the RubberBand to zoom in and out relative to the size of the box I would like to zoom in the view to fit whatever is inside the block to the full view.
Can anyone help?
The zoom in and out with the mouse works as expected.
You can see in the code the rubberband works but I don't know how to make the zoom relative to the size of the box.
code:
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys
from math import sqrt
class Point(QGraphicsItem):
def __init__(self, x, y):
super(Point, self).__init__()
self.setFlag(QGraphicsItem.ItemIsSelectable, True)
self.rectF = QRectF(0, 0, 30, 30)
self.x=x
self.y=y
self._brush = QBrush(Qt.black)
def setBrush(self, brush):
self._brush = brush
self.update()
def boundingRect(self):
return self.rectF
def paint(self, painter=None, style=None, widget=None):
painter.fillRect(self.rectF, self._brush)
def hoverMoveEvent(self, event):
point = event.pos().toPoint()
print(point)
QGraphicsItem.hoverMoveEvent(self, event)
class Viewer(QGraphicsView):
photoClicked = pyqtSignal(QPoint)
rectChanged = pyqtSignal(QRect)
def __init__(self, parent):
super(Viewer, self).__init__(parent)
self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
self.setMouseTracking(True)
self.origin = QPoint()
self.changeRubberBand = False
self._zoom = 0
self._empty = True
self._scene = QGraphicsScene(self)
self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
self.setResizeAnchor(QGraphicsView.AnchorUnderMouse)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setFrameShape(QFrame.NoFrame)
self.area = float()
self.setPoints()
def setItems(self):
self.data = {'x': [-2414943.8686, -2417160.6592, -2417160.6592, -2417856.1783, -2417054.7618, -2416009.9966, -2416012.5232, -2418160.8952, -2418160.8952, -2416012.5232, -2417094.7694, -2417094.7694], 'y': [10454269.7008,
10454147.2672, 10454147.2672, 10453285.2456, 10452556.8132, 10453240.2808, 10455255.8752, 10455183.1912, 10455183.1912, 10455255.8752, 10456212.5959, 10456212.5959]}
maxX = max(self.data['x'])
minX = min(self.data['x'])
maxY = max(self.data['y'])
minY = min(self.data['y'])
distance = sqrt((maxX-minX)**2+(maxY-minY)**2)
self.area = QRectF(minX, minY, distance, distance)
for i,x in enumerate(self.data['x']):
x = self.data['x'][i]
y = self.data['y'][i]
p = Point(x,y)
p.setPos(x,y)
self._scene.addItem(p)
self.setScene(self._scene)
def fitInView(self, scale=True):
rect = QRectF(self.area)
if not rect.isNull():
self.setSceneRect(rect)
unity = self.transform().mapRect(QRectF(0, 0, 1, 1))
self.scale(1 / unity.width(), 1 / unity.height())
viewrect = self.viewport().rect()
scenerect = self.transform().mapRect(rect)
factor = min(viewrect.width() / scenerect.width(),
viewrect.height() / scenerect.height())
self.scale(factor, factor)
self._zoom = 0
def setPoints(self):
self._zoom = 0
self.setItems()
self.setDragMode(True)
self.fitInView()
def wheelEvent(self, event):
if event.angleDelta().y() > 0:
factor = 1.25
self._zoom += 1
else:
factor = 0.8
self._zoom -= 1
if self._zoom > 0:
self.scale(factor, factor)
elif self._zoom == 0:
self.fitInView()
else:
self._zoom = 0
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.origin = event.pos()
self.rubberBand.setGeometry(QRect(self.origin, QSize()))
self.rectChanged.emit(self.rubberBand.geometry())
self.rubberBand.show()
self.changeRubberBand = True
return
#QGraphicsView.mousePressEvent(self,event)
elif event.button() == Qt.MidButton:
self.viewport().setCursor(Qt.ClosedHandCursor)
self.original_event = event
handmade_event = QMouseEvent(QEvent.MouseButtonPress,QPointF(event.pos()),Qt.LeftButton,event.buttons(),Qt.KeyboardModifiers())
QGraphicsView.mousePressEvent(self,handmade_event)
super(Viewer, self).mousePressEvent(event)
def mouseReleaseEvent(self, event):
if event.button() == Qt.LeftButton:
self.origin = event.pos()
self.rubberBand.setGeometry(QRect(self.origin, QSize()))
self.changeRubberBand = False
QGraphicsView.mouseReleaseEvent(self,event)
elif event.button() == Qt.MidButton:
self.viewport().setCursor(Qt.OpenHandCursor)
handmade_event = QMouseEvent(QEvent.MouseButtonRelease,QPointF(event.pos()),Qt.LeftButton,event.buttons(),Qt.KeyboardModifiers())
QGraphicsView.mouseReleaseEvent(self,handmade_event)
super(Viewer, self).mouseReleaseEvent(event)
def mouseMoveEvent(self, event):
if self.changeRubberBand:
self.rubberBand.setGeometry(QRect(self.origin, event.pos()).normalized())
self.rectChanged.emit(self.rubberBand.geometry())
QGraphicsView.mouseMoveEvent(self,event)
super(Viewer, self).mouseMoveEvent(event)
class Window(QWidget):
def __init__(self):
super(Window, self).__init__()
self.viewer = Viewer(self)
self.btnLoad = QToolButton(self)
self.btnLoad.setText('Load Points')
self.btnLoad.clicked.connect(self.loadPoints)
VBlayout = QVBoxLayout(self)
VBlayout.addWidget(self.viewer)
HBlayout = QHBoxLayout()
HBlayout.setAlignment(Qt.AlignLeft)
HBlayout.addWidget(self.btnLoad)
VBlayout.addLayout(HBlayout)
def loadPoints(self):
self.viewer.setPoints()
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
window = Window()
window.setGeometry(500, 300, 800, 600)
window.show()
sys.exit(app.exec_())
in my code I have two comboboxes inside and I intentionally designed a frameless borderless window; so I had to define mouse events manually to move window on click and drag, and resizing on edges.
without comboboxes it works perfectly, but somehow clicking on combos to open them trigger only mouseMoveEvent and not mousePressEvent, causing an error about there is no self.old_Pos. if we uncomment last three lines of init function, this error is gone, but on openning combos whole window will be displaced. how can I overcome this problem?
from PyQt5.QtWidgets import *
from PyQt5 import QtCore
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class MainWindow(QWidget):
switch_window = QtCore.pyqtSignal()
def __init__(self):
QWidget.__init__(self)
self.combo1 = QComboBox()
for i in range (0,10):
self.combo1.addItem('Combo1 label %s' %str(i))
self.combo2 = QComboBox()
for i in range (0,15):
self.combo2.addItem('Combo1 label %s' %str(i))
main_layout = QVBoxLayout()
layout = QHBoxLayout()
layout.addWidget(self.combo1)
layout.addWidget(self.combo2)
# design title bar
title_bar = QHBoxLayout()
title_bar.setObjectName('HeaderBar')
title_bar.setContentsMargins(0,0,0,0)
title = QLabel('title bar')
btn_size = 35
btn_close = QPushButton("x")
btn_close.clicked.connect(self.btn_close_clicked)
btn_close.setFixedSize(btn_size,btn_size)
btn_close.setStyleSheet("background-color: red;")
btn_min = QPushButton("_")
btn_min.clicked.connect(self.btn_min_clicked)
btn_min.setFixedSize(btn_size, btn_size)
btn_min.setStyleSheet("background-color: gray;")
self.btn_max = QPushButton("+")
self.btn_max.clicked.connect(self.btn_max_clicked)
self.btn_max.setFixedSize(btn_size, btn_size)
self.btn_max.setStyleSheet("background-color: gray;")
title.setAlignment(Qt.AlignCenter)
title_bar.addWidget(title)
title_bar.addWidget(btn_min)
title_bar.addWidget(self.btn_max)
title_bar.addWidget(btn_close)
main_layout.addLayout(title_bar)
main_layout.addLayout(layout)
self.setWindowFlags(Qt.FramelessWindowHint)
self.setLayout(main_layout)
#self.old_Pos = QPoint(0,0)
#self.old_width = self.width()
#self.old_height = self.height()
def mousePressEvent(self, event):
self.old_Pos = event.globalPos()
self.old_width = self.width()
self.old_height = self.height()
def mouseMoveEvent(self, event):
delta = QPoint (event.globalPos() - self.old_Pos)
if (self.old_Pos.x() > self.x() + self.old_width - 10) or (self.old_Pos.y() > self.y() + self.old_height - 10):
self.setFixedSize(self.old_width + delta.x(),self.old_height + delta.y())
else:
self.move(self.x() + delta.x(), self.y() + delta.y())
self.old_Pos = event.globalPos()
def btn_close_clicked(self):
quit()
def btn_max_clicked(self):
if self.isMaximized():
self.showNormal()
self.btn_max.setText('+')
else:
self.showMaximized()
self.btn_max.setText('R')
def btn_min_clicked(self):
self.showMinimized()
app = QApplication([])
mainapp = MainWindow()
mainapp.show()
app.exec_()
I believe I solved this problem.
all we have to do is to define self.old_Pos = None inside __init__ and mouseReleaseEvent, and put an if self.old_Pos: statement inside mouseMoveEvent.
here is the code:
from PyQt5.QtWidgets import *
from PyQt5 import QtCore
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class MainWindow(QWidget):
switch_window = QtCore.pyqtSignal()
def __init__(self):
QWidget.__init__(self)
self.combo1 = QComboBox()
for i in range (0,10):
self.combo1.addItem('Combo1 label %s' %str(i))
self.combo2 = QComboBox()
for i in range (0,15):
self.combo2.addItem('Combo2 label %s' %str(i))
main_layout = QVBoxLayout()
layout = QHBoxLayout()
layout.addWidget(self.combo1)
layout.addWidget(self.combo2)
# design title bar
title_bar = QHBoxLayout()
title_bar.setObjectName('HeaderBar')
title_bar.setContentsMargins(0,0,0,0)
title = QLabel('title bar')
btn_size = 35
btn_close = QPushButton("x")
btn_close.clicked.connect(self.btn_close_clicked)
btn_close.setFixedSize(btn_size,btn_size)
btn_close.setStyleSheet("background-color: red;")
btn_min = QPushButton("_")
btn_min.clicked.connect(self.btn_min_clicked)
btn_min.setFixedSize(btn_size, btn_size)
btn_min.setStyleSheet("background-color: gray;")
self.btn_max = QPushButton("+")
self.btn_max.clicked.connect(self.btn_max_clicked)
self.btn_max.setFixedSize(btn_size, btn_size)
self.btn_max.setStyleSheet("background-color: gray;")
title.setAlignment(Qt.AlignCenter)
title_bar.addWidget(title)
title_bar.addWidget(btn_min)
title_bar.addWidget(self.btn_max)
title_bar.addWidget(btn_close)
main_layout.addLayout(title_bar)
main_layout.addLayout(layout)
self.setWindowFlags(Qt.FramelessWindowHint)
self.setLayout(main_layout)
self.work_with_combo = True
self.old_Pos = None
def mousePressEvent(self, event):
self.old_Pos = event.globalPos()
self.old_width = self.width()
self.old_height = self.height()
def mouseMoveEvent(self, event):
if self.old_Pos:
delta = QPoint (event.globalPos() - self.old_Pos)
if (self.old_Pos.x() > self.x() + self.old_width - 10) or (self.old_Pos.y() > self.y() + self.old_height - 10):
self.setFixedSize(self.old_width + delta.x(),self.old_height + delta.y())
else:
self.move(self.x() + delta.x(), self.y() + delta.y())
self.old_Pos = event.globalPos()
def mouseReleaseEvent(self, event):
self.old_Pos = None
def btn_close_clicked(self):
quit()
def btn_max_clicked(self):
if self.isMaximized():
self.showNormal()
self.btn_max.setText('+')
else:
self.showMaximized()
self.btn_max.setText('R')
def btn_min_clicked(self):
self.showMinimized()
app = QApplication([])
mainapp = MainWindow()
mainapp.show()
app.exec_()
I have been searching for this solution FOREVER. Just wanted to thank you so much for posting the solution. Worked perfectly for me!
For anyone using just Qt Creator, here is the ultimate code I used:
//Declare oldPos in .h private
QPoint oldPos = QPoint();
void GiftCardDialog::mousePressEvent(QMouseEvent* event) {
oldPos = event->globalPos();
}
void GiftCardDialog::mouseReleaseEvent(QMouseEvent *event) {
(void)event;
oldPos = QPoint();
}
void GiftCardDialog::mouseMoveEvent(QMouseEvent* event) {
if(!oldPos.isNull()) {
QPoint delta = event->globalPos() - oldPos;
if(oldPos.x() > this->x() + this->width() - 10
|| oldPos.y() > this->y() + this->height() - 10) {
} else {
move(this->x() + delta.x(), this->y() + delta.y());
oldPos = event->globalPos();
}
}
}
I just made this program as a practice I want to make the circle bounce from end to end which I came up in this source codes can you make if happen.
import PyQt5,sys
from PyQt5 import QtCore,QtGui,QtWidgets
from PyQt5.QtCore import Qt,QTimer,QPoint
from PyQt5.QtWidgets import QWidget,QApplication,QMainWindow
from PyQt5.QtGui import QPainter
class Circle(QWidget):
def __init__(self):
QMainWindow.__init__(self)
self.resize(250,500)
self.setWindowTitle("Bounce-Man")
self.color = Qt.red
self.fixedplace = 125
self.mover = 450
def paintEvent(self,event):
bouncer.setPen(Qt.black)
bouncer.setBrush(self.color)
bouncer.drawEllipse(QPoint(self.fixedplace,self.mover),50,50)
#QtCore.pyqtSlot()
def timer(self):
timer = QTimer()
while self.mover >=50:
timer.start(1000)
if self.mover == 50:
self.mover = 450
self.mover -= 1
self.update()
if __name__ == "__main__":
window = QApplication(sys.argv)
app = Circle()
app.show()
sys.exit( window.exec_() )
You must use a QTimer to call a function that updates the position, do not use a while loop:
from PyQt5 import QtCore, QtGui, QtWidgets
class Circle(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Circle, self).__init__(parent)
self.resize(250,500)
self.setWindowTitle("Bounce-Man")
self.color = QtGui.QColor(QtCore.Qt.red)
self.rect_circle = QtCore.QRect(0, 0, 50, 50)
self.rect_circle.moveCenter(QtCore.QPoint(self.width()/2, self.rect_circle.height()/2))
self.step = QtCore.QPoint(0, 5)
self.y_direction = 1
timer = QtCore.QTimer(self, interval=30)
timer.timeout.connect(self.update_position)
timer.start()
def paintEvent(self,event):
bouncer = QtGui.QPainter(self)
bouncer.setPen(QtCore.Qt.black)
bouncer.setBrush(self.color)
bouncer.drawEllipse(self.rect_circle)
#QtCore.pyqtSlot()
def update_position(self):
if self.rect_circle.bottom() > self.height() and self.y_direction == 1:
self.y_direction = -1
if self.rect_circle.top() < 0 and self.y_direction == -1:
self.y_direction = 1
self.rect_circle.translate(self.step * self.y_direction)
self.update()
if __name__ == "__main__":
import sys
window = QtWidgets.QApplication(sys.argv)
app = Circle()
app.show()
sys.exit( window.exec_() )
I want to change an image with my mouse. So, everytime I click somewhere, the image should change. I can show an image only one time. So I need to separate the initialization of everything that is needed to show an image from the part of code that is responsable for building an image.
Here is what I have got by far
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import pyqtSlot
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
self.gx=1
self.gy=1
self.tlb=QLabel()
self.lbl=QLabel()
self.image = QImage(512, 512, QImage.Format_RGB32)
self.hbox = QHBoxLayout()
self.pixmap = QPixmap()
self.initUI()
def mousePressEvent(self, QMouseEvent):
px = QMouseEvent.pos().x()
py = QMouseEvent.pos().y()
size = self.frameSize()
self.gx = px-size.width()/2
self.gy = py-size.height()/2
self.fillImage()
def initUI(self):
self.hbox = QHBoxLayout(self)
self.pixmap = QPixmap()
size = self.frameSize()
self.fillImage()
self.lbl = QLabel(self)
self.lbl.setPixmap(self.pixmap)
self.hbox.addWidget(self.lbl)
self.setLayout(self.hbox)
self.move(300, 200)
self.setWindowTitle('Red Rock')
self.tlb = QLabel(str(self.gx)+" : "+str(self.gy), self)
self.tlb.move(12,3)
self.show()
def fillImage(self):
for x in range(0, 512):
t = -1+(x/512)*2
color = (1 - (3 - 2*abs(t))*t**2)
for y in range(0, 512):
t1 = -1+(y/512)*2
color1 = (1 - (3 - 2*abs(t1))*t1**2)
result = (255/2)+(color * color1 * (t*self.gx+t1*self.gy) )*(255/2)
self.image.setPixel(x, y, qRgb(result, result, result))
self.pixmap = self.pixmap.fromImage(self.image)
self.tlb = QLabel(str(self.gx)+" : "+str(self.gy), self)
print(self.gx)
self.update()
def main():
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
The print(self.gx) shows me that self.gx is changed, but the image isn't changed at all.
What do I do wrong?
You will have to tell the GUI that it needs to refresh the image.
In QT it seems you will need to call the update() or repaint() methods of the widget.
I've added self.lbl.setPixmap(self.pixmap) into fillImage before self.repaint() and self.update() and now it works, then i changed a little the code and now it looks like this
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import pyqtSlot
class Example(QWidget):
def __init__(self):
super(Example, self).__init__()
self.gx=1
self.gy=1
self.lbl=QLabel()
self.tlb = None
self.image = QImage(512, 512, QImage.Format_RGB32)
self.hbox = QHBoxLayout()
self.pixmap = QPixmap()
self.length = 1
self.initUI()
def mousePressEvent(self, QMouseEvent):
px = QMouseEvent.pos().x()
py = QMouseEvent.pos().y()
size = self.frameSize()
self.gx = px-size.width()/2
self.gy = py-size.height()/2
h = (self.gx**2+self.gy**2)**0.5
self.gx/=h
self.gy/=h
self.gx*=self.length
self.gy*=self.length
self.fillImage()
def wheelEvent(self,event):
self.length+=(event.delta()*0.001)
print(self.length)
def initUI(self):
self.hbox = QHBoxLayout(self)
self.pixmap = QPixmap()
self.move(300, 200)
self.setWindowTitle('Red Rock')
self.addedWidget = None
self.fillImage()
self.setLayout(self.hbox)
self.show()
def fillImage(self):
for x in range(0, 512):
t = -1+(x/512)*2
color = (1 - (3 - 2*abs(t))*t**2)
for y in range(0, 512):
t1 = -1+(y/512)*2
color1 = (1 - (3 - 2*abs(t1))*t1**2)
result = (255/2)+(color * color1 * (t*self.gx+t1*self.gy) )*(255/2)
self.image.setPixel(x, y, qRgb(result, result, result))
self.pixmap = self.pixmap.fromImage(self.image)
if self.lbl == None:
self.lbl = QLabel(self)
else:
self.lbl.setPixmap(self.pixmap)
if self.addedWidget == None:
self.hbox.addWidget(self.lbl)
self.addedWidget = True
if self.tlb==None:
self.tlb = QLabel(str(self.gx)+" : "+str(self.gy), self)
self.tlb.move(12,3)
else:
self.tlb.setText(str(self.gx)+" : "+str(self.gy))
self.repaint()
self.update()
def main():
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()