raiseTemmie.py
import random
import sys
import time
from PyQt5.QtGui import QPixmap
from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtWidgets import QWidget, QLabel, QApplication
class Example(QWidget):
size=100
imgNum=0
imgQuantity=2
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowFlags(Qt.FramelessWindowHint)
self.setAttribute(Qt.WA_TranslucentBackground)
self.setStyleSheet("background-color:transparent;")
self.setGeometry(100, 100, 100, 100)
self.setWindowFlags(Qt.SplashScreen | Qt.WindowStaysOnTopHint)
self.label=QLabel(self)
self.pixmaps=[QPixmap('left.png'),QPixmap('right.png'),QPixmap('stand.png')]
for x in range(len(self.pixmaps)):
self.pixmaps[x]=self.pixmaps[x].scaled(self.size,self.size,Qt.KeepAspectRatio)
self.label.setPixmap(self.pixmaps[2])
self.resize(self.pixmaps[2].width(),self.pixmaps[2].height())
self.show()
def moving(self):
distance=random.randint(10,40)
direct =[random.randint(-1,2),random.randint(-1,2)]
for x in range(0,distance):
self.changeFoot()
self.move(self.x()+5*direct[0],self.y()+5*direct[1])
time.sleep(0.05)
# self.changeTimer.stop()
def changeFoot(self):
if self.imgNum<self.imgQuantity-1:
self.imgNum+=1
else :
self.imgNum=0
self.label.setPixmap(self.pixmaps[self.imgNum])
def mousePressEvent(self, QMouseEvent):
self.label.setPixmap(self.pixmaps[2])
self.changeTimer.stop()
changeTimer=QTimer()
def keyPressEvent(self, QKeyEvent):
if QKeyEvent.key() == Qt.Key_Escape:
sys.exit()
if QKeyEvent.key() == Qt.Key_G:
self.moving()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
I thought this code would switch the pixmap and move it simultaneously but it do not work well.
The timer start after moving finished. What is the problem?
def keyPressEvent(self, QKeyEvent):
if QKeyEvent.key() == Qt.Key_Escape:
sys.exit()
if QKeyEvent.key() == Qt.Key_G:
self.moving()
if I press 'G', it starts the changeTimer and calls moving()
A possible solution is to use qApp.processEvents() to update the data, this is recommended when tasks require little time as is your case, since the maximum time of the loop is 0.05sec*40=2sec.
def moving(self):
distance=random.randint(10,40)
direct =[random.randint(-1,2),random.randint(-1,2)]
for x in range(0,distance):
self.changeFoot()
self.move(self.x()+5*direct[0],self.y()+5*direct[1])
time.sleep(0.05)
qApp.processEvents()
The solution may fail if time grows, another solution is to implement the timer and separate the tasks correctly as I show below:
class Example(QWidget):
size=100
imgNum=0
imgQuantity=2
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowFlags(Qt.FramelessWindowHint)
self.setAttribute(Qt.WA_TranslucentBackground)
self.setStyleSheet("background-color:transparent;")
self.setGeometry(100, 100, 100, 100)
self.setWindowFlags(Qt.SplashScreen | Qt.WindowStaysOnTopHint)
self.label=QLabel(self)
self.pixmaps=[QPixmap('left.png'),QPixmap('right.png'),QPixmap('stand.png')]
for x in range(len(self.pixmaps)):
self.pixmaps[x]=self.pixmaps[x].scaled(self.size,self.size,Qt.KeepAspectRatio)
self.label.setPixmap(self.pixmaps[2])
self.resize(self.pixmaps[2].width(),self.pixmaps[2].height())
self.changeTimer=QTimer(self)
self.changeTimer.timeout.connect(self.onTimeout)
self.show()
def moving(self):
self.distance= random.randint(10,40)
self.direct = QPoint(random.randint(-1,2), random.randint(-1,2))
self.changeTimer.start(50)
def onTimeout(self):
if self.distance == 0:
self.changeTimer.stop()
else:
self.changeFoot()
self.move(self.pos() + self.direct)
self.distance -= 1
def changeFoot(self):
if self.imgNum<self.imgQuantity-1:
self.imgNum+=1
else :
self.imgNum=0
self.label.setPixmap(self.pixmaps[self.imgNum])
def mousePressEvent(self, QMouseEvent):
self.label.setPixmap(self.pixmaps[2])
self.changeTimer.stop()
def keyPressEvent(self, QKeyEvent):
if QKeyEvent.key() == Qt.Key_Escape:
self.close()
if QKeyEvent.key() == Qt.Key_G:
self.moving()
Note: It is advisable to use self.close() instead of sys.exit() since the first gives time for the program to free resources and close properly.
Related
I am writing a slot method for the signal of scrolling down a scrollbar in QPlainTextEdit.
I only found this signalQPlainTextEdit.verticalScrollBar().valueChanged.
I tested this signal and it returned the position number when scrolls to a new position.
My purpose is that when the scrollbar move down and trigger the slot method. But in that signal when move up it also triggeres the slot.
I read the document but I couldn't find other signals.
A possible solution is to save the previous position and compare with the new position using sliderPosition property:
from PyQt5.QtWidgets import QApplication, QPlainTextEdit
class PlainTextEdit(QPlainTextEdit):
def __init__(self, parent=None):
super().__init__(parent)
self.last_position = self.verticalScrollBar().sliderPosition()
self.verticalScrollBar().sliderMoved.connect(self.handle_value_changed)
def handle_value_changed(self, position):
if position > self.last_position:
print("down")
else:
print("up")
self.last_position = position
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
w = PlainTextEdit()
w.show()
sys.exit(app.exec_())
Another possible option is to implement a use of the mousePressEvent and mouseMoveEvent events of the QScrollBar:
from PyQt5.QtCore import QPoint, Qt
from PyQt5.QtWidgets import QApplication, QPlainTextEdit, QScrollBar
class ScrollBar(QScrollBar):
last_pos = QPoint()
def mousePressEvent(self, event):
self.last_pos = event.pos()
super().mousePressEvent(event)
def mouseMoveEvent(self, event):
super().mouseMoveEvent(event)
if event.pos().y() > self.last_pos.y():
print("down")
else:
print("up")
self.last_pos = event.pos()
class PlainTextEdit(QPlainTextEdit):
def __init__(self, parent=None):
super().__init__(parent)
self.vertical_scrollbar = ScrollBar(Qt.Vertical)
self.setVerticalScrollBar(self.vertical_scrollbar)
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
w = PlainTextEdit()
w.show()
sys.exit(app.exec_())
OR:
from PyQt5.QtCore import QEvent, QPoint
from PyQt5.QtWidgets import QApplication, QPlainTextEdit
class PlainTextEdit(QPlainTextEdit):
def __init__(self, parent=None):
super().__init__(parent)
self.last_pos = QPoint()
self.verticalScrollBar().installEventFilter(self)
def eventFilter(self, obj, event):
if obj is self.verticalScrollBar():
if event.type() == QEvent.MouseButtonPress:
self.last_pos = event.pos()
elif event.type() == QEvent.MouseMove:
if event.pos().y() > self.last_pos.y():
print("down")
else:
print("up")
self.last_pos = event.pos()
return super().eventFilter(obj, event)
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
w = PlainTextEdit()
w.show()
sys.exit(app.exec_())
My code looks like this
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setGeometry(400, 400, 600, 480)
self.setWindowTitle("HBCheat")
self.initUI()
def initUI(self):
self.label = QtWidgets.QLabel(self)
self.label.setText("Reaction Cheat")
self.label.move(10, 0)
self.b1 = QtWidgets.QPushButton(self)
self.b1.setText("Toggle: off")
self.b1.move(10, 35)
self.b1.clicked.connect(self.reaction_cheat)
def click(self,x,y):
win32api.SetCursorPos((x,y))
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,0,0)
time.sleep(0.01)
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,0,0)
def reaction_cheat(self):
self.b1.setText("Toggle: on")
while not keyboard.is_pressed('q'):
try:
if pyautogui.pixel(1298, 415)[1] == 219:
self.click(1298, 415)
except:
continue
self.b1.setText("Toggle: off")
Whenever I click on button "b1" it should run the function reaction_cheat. Which it does. But the problem is that the text for the button does not change and the window crashes. If I press the button it still works as intended but the button text does not change. And if I were to comment out the "while not keyboard.is_pressed('q'):" loop. It would change the buttons text and the function would end.
So Why is it that the the text for b1 doesn't change and the window crashes.
Also when I press q it doesn't stop the window from crashes. But it still stops the loop and stops the function from running.
The problem is caused because the logic that checks if the key q is pressed or does not consume a lot of time blocking the eventloop.
A possible solution is to use threads but another solution is to use the add_hotkey function that allows to use a callback avoiding the use of while loops. You should also avoid using time.sleep(). In this case the logic is that if the button is pressed then the task of verifying the pixel will be executed every T seconds until the user presses the q key.
from functools import cached_property
from PyQt5.QtCore import pyqtSignal, QObject, QTimer
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QPushButton
import pyautogui
import keyboard
import win32api
import win32con
class KeyBoardHelper(QObject):
pressed = pyqtSignal()
def __init__(self, hotkey="", parent=None):
super().__init__(parent)
self._hotkey = hotkey
#property
def hotkey(self):
return self._hotkey
#hotkey.setter
def hotkey(self, hotkey):
self.stop()
self._hotkey = hotkey
def start(self):
keyboard.add_hotkey(self.hotkey, self._callback)
def stop(self):
try:
keyboard.remove_hotkey(self._callback)
except KeyError:
pass
def _callback(self):
self.pressed.emit()
class MouseHelper:
def click(self, x, y):
win32api.SetCursorPos((x, y))
self._press()
def _press(self):
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, 0, 0)
QTimer.singleShot(10, self._release)
def _release(self):
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0, 0)
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setGeometry(400, 400, 600, 480)
self.setWindowTitle("HBCheat")
self.initUI()
self.keyboard_helper.pressed.connect(self.handle_keyboard_pressed)
self.keyboard_helper.hotkey = "q"
self.timer.timeout.connect(self.verify_pixel)
#cached_property
def keyboard_helper(self):
return KeyBoardHelper()
#cached_property
def mouse_helper(self):
return MouseHelper()
#cached_property
def timer(self):
return QTimer(interval=10)
def initUI(self):
self.label = QLabel(self)
self.label.setText("Reaction Cheat")
self.label.move(10, 0)
self.b1 = QPushButton(self)
self.b1.setText("Toggle: off")
self.b1.move(10, 35)
self.b1.clicked.connect(self.reaction_cheat)
def click(self, x, y):
print("X")
""""
"""
def reaction_cheat(self):
self.b1.setText("Toggle: on")
self.keyboard_helper.start()
self.timer.start()
def handle_keyboard_pressed(self):
self.keyboard_helper.stop()
self.timer.start()
self.b1.setText("Toggle: off")
def verify_pixel(self):
try:
if pyautogui.pixel(1298, 415)[1] == 219:
self.mouse_helper.click(1298, 415)
except:
pass
def main():
import sys
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
I'm setting up a new desktop widget to make my life easier at work and using QPropertyAnimation to make it pretty. Fading the app in and out doesn't seem to want to work and in typical coder fashion, it's brought my progress to a standstill.
I'm implementing QPropertyAnimation in a personalised class to make my life easier, but since it's not intially worked I've taken it back to the class code and it's still being pretty stubborn. So far I've tried.
class widget(QWidget):
def init(self):
self.setSize(QSize(300, 300))
self.setWindowOpacity(1)
self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
self.setAttribute(Qt.WA_TranslucentBackground)
def paintEvent(self, event):
s = self.size()
qp = QPainter()
qp.begin(self)
qp.setRenderHint(QPainter.Antialiasing, True)
qp.setBrush(QColor().fromRgb(2,106,194))
qp.setPen(QColor().fromRgb(2,106,194))
qp.drawRoundRect(QRect(0,0, 300, 300), 16, 8)
qp.end()
def show(self):
self.superShow()
a = QPropertyAnimation(self, "windowOpacity")
a.setDuration(500)
a.setStartValue(1)
a.setEndValue(0)
a.start()
def hide(self):
a = QPropertyAnimation(self, "windowOpacity")
a.setDuration(500)
a.setStartValue(0)
a.setEndValue(1)
a.finished.connect(self.superHide)
a.start()
def superShow(self):
super(widget, self).show()
def superHide(self):
super(widget, self).hide()
No error messages at all it just hides and shows after the animation duration is over. No idea where to look or what to do to get it working. I've only been coding for like 3 months or so.
Your code has many errors, for example:
I don't see where you call init().
Animations are local variables that will be removed when the show and hide methods are finished, which is almost instantaneous.
etc.
Instead of changing the opacity directly I will use QGraphicsOpacityEffect, instead of using the show and close method, I will use the showEvent, hideEvent and closeEvent methods.
import sys
from PySide2.QtCore import QEasingCurve, QEventLoop, QPropertyAnimation, QRect, QSize, Qt
from PySide2.QtGui import QColor, QPainter
from PySide2.QtWidgets import QAction, QApplication, QGraphicsOpacityEffect, QWidget
class Widget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.resize(QSize(300, 300))
# self.setWindowOpacity(1)
self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
self.setAttribute(Qt.WA_TranslucentBackground)
self.setContextMenuPolicy(Qt.ActionsContextMenu)
quit_action = QAction(self.tr("E&xit"), self)
quit_action.setShortcut(self.tr("Ctrl+Q"))
quit_action.triggered.connect(self.close)
self.addAction(quit_action)
effect = QGraphicsOpacityEffect(self, opacity=1.0)
self.setGraphicsEffect(effect)
self._animation = QPropertyAnimation(
self,
propertyName=b"opacity",
targetObject=effect,
duration=500,
startValue=0.0,
endValue=1.0,
)
def paintEvent(self, event):
qp = QPainter(self)
qp.setRenderHint(QPainter.Antialiasing, True)
qp.setBrush(QColor().fromRgb(2, 106, 194))
qp.setPen(QColor().fromRgb(2, 106, 194))
qp.drawRoundedRect(QRect(0, 0, 300, 300), 16, 8)
def fade_in(self):
self._animation.setDirection(QPropertyAnimation.Forward)
self._animation.start()
def fade_out(self):
loop = QEventLoop()
self._animation.finished.connect(loop.quit)
self._animation.setDirection(QPropertyAnimation.Backward)
self._animation.start()
loop.exec_()
def showEvent(self, event):
super().showEvent(event)
self.fade_in()
def closeEvent(self, event):
# fade out
self.fade_out()
super().closeEvent(event)
def hideEvent(self, event):
# fade out
self.fade_out()
super().hideEvent(event)
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
I want that if I move my mouse over the label with text stop on it then it should change the value of a variable Stop to True so that I may pause/stop my program.
I have looked the code at
Mouseover event filter for a PyQT Label
and tried to run it, but nothing is being shown up.
The code is:
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5 import *
import sys
class mouseoverEvent(QtCore.QObject):
def __init__(self, parent):
super(mouseoverEvent, self).__init__(parent)
self.initUI()
def eventFilter(self, object, event):
if event.type() == QtCore.QEvent.MouseMove:
print( "mousemove!")
return True
else:
return False
def initUI(self):
self.filter = mouseoverEvent(self)
self.label.installEventFilter(self.filter)
self.lbl=QLabel(self)
self.lbl.setText(self,"hellojjj")
self.setGeometry(1000, 30, 300, 100)
self.setWindowTitle('QLineEdit')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = mouseoverEvent()
sys.exit(app.exec_())
If you've already imported
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
there is no need to
from PyQt5 import *
Once you've imported QtCore, you no longer need to call its functions/classes with 'QtCore.QEvent', Just using QEvent is fine
I believe the question you linked to used PyQt4. In PyQt5, the initialization procedure for the class changed
The code below should work.
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
class mouseoverEvent(QWidget):
def __init__(self):
super().__init__()
self.stop = False # your 'stop' variable
self.initUI()
def initUI(self):
self.lbl=QLabel(self)
self.lbl.setText("Hover over me to stop the program")
self.lbl.installEventFilter(self)
self.setGeometry(1000, 30, 300, 100)
self.setWindowTitle('QLineEdit')
self.show()
def eventFilter(self, object, event):
if event.type() == QEvent.Enter:
print("Mouse is over the label")
self.stop = True
print('program stop is', self.stop)
return True
elif event.type() == QEvent.Leave:
print("Mouse is not over the label")
self.stop = False
print('program stop is', self.stop)
return False
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = mouseoverEvent()
sys.exit(app.exec_())
if you only want the stop to activate over a label with certain text change your eventFilter function to:
def eventFilter(self, object, event):
if hasattr(object, 'text'): #check to see if the object has text, otherwise if you hover over something without text, PyQt will return an error
if object.text() == "Hover over me to stop the program":
if event.type() == QEvent.Enter:
print("Mouse is over the label")
self.stop = True
print('program stop is', self.stop)
return True
elif event.type() == QEvent.Leave:
print("Mouse is not over the label")
self.stop = False
print('program stop is', self.stop)
return False
Remember that Python is very flexible, so there is no need to subclass QLabel.
For example:
def enter(event):
print("Enter")
def leave(label):
print("Leave")
label = QLabel("Hello")
label.leaveEvent = leave
label.enterEvent = enter
Or you can use lambdas:
label = QLabel("Hello")
label.leaveEvent = lambda e: print("Leave")
label.enterEvent = lambda e: print("Enter")
Please find the reference:
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
class Label(QLabel):
def __init__(self, *args, **kwargs):
QLabel.__init__(self, *args, **kwargs)
def enterEvent(self, event):
print("hovered")
def leaveEvent(self, event):
print("left")
I want to draw a line consisting of multiple points via mouse click in a Python script using PyQt. I need all coordinates of the ponts and I want to be able to delete the line. Here's my script doing all the work, except for the graphical line drawing itself, it just prints what it does:
#!/usr/bin/python3
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class endomess(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.draw = False
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
if self.draw == False:
print('Starting to draw at', str(event.pos()))
self.draw = True
self.linePoints = []
elif self.draw == True:
print('Appending', str(event.pos()))
self.linePoints.append(event.pos())
elif event.button() == Qt.RightButton:
if self.draw == True:
print('Finished drawing. List of all points:', str(self.linePoints))
self.draw = False
def main(argv):
app = QApplication(argv, True)
wnd = endomess()
wnd.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main(sys.argv)
So, here's my problem: how do I actually draw that line that can be defined via the above script? I already had a look at scribble.py and some Qt paint docs, but I don't get it. Probably, this is not a problem for someone more experienced with Qt?
Thanks in advance for all help!
You should probably use the graphics view framework for drawing the lines, rather than attempting to paint them directly.
Here's a basic demo to get you started:
from PyQt4 import QtGui, QtCore
class Window(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.view = View(self)
self.button = QtGui.QPushButton('Clear View', self)
self.button.clicked.connect(self.handleClearView)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.view)
layout.addWidget(self.button)
def handleClearView(self):
self.view.scene().clear()
class View(QtGui.QGraphicsView):
def __init__(self, parent):
QtGui.QGraphicsView.__init__(self, parent)
self.setScene(QtGui.QGraphicsScene(self))
self.setSceneRect(QtCore.QRectF(self.viewport().rect()))
def mousePressEvent(self, event):
self._start = event.pos()
def mouseReleaseEvent(self, event):
start = QtCore.QPointF(self.mapToScene(self._start))
end = QtCore.QPointF(self.mapToScene(event.pos()))
self.scene().addItem(
QtGui.QGraphicsLineItem(QtCore.QLineF(start, end)))
for point in (start, end):
text = self.scene().addSimpleText(
'(%d, %d)' % (point.x(), point.y()))
text.setBrush(QtCore.Qt.red)
text.setPos(point)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.resize(640, 480)
window.show()
sys.exit(app.exec_())