Pyside6 mouse coordinate relative to image - python-3.x

Let suppose I have an image correctly rendered in a QLabel
As I want to get mouse position relative to the image I'm subclassing QLabel and reimplant mouseMoveEvent(self,event) and then build the source_image from this class.Rendering is Ok, but how do I get the event.x() from the parent class ?
I know I have to connect the instance to the ImLabel signals but i'm stuck with implementation.
class ImLabel(QLabel):
def __init__(self):
super().__init__()
on_mouse_move = Signal()
def mouseMoveEvent(self, event):
print(event.x(), event.y())
super(ImLabel, self).mouseMoveEvent(event)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.source_image = ImLabel()
self.source_image.on_mouse_move.connect(self.mouseMoveEvent)
...
self.cursor = QLabel("cursor : ")
...
def mouseMoveEvent(self,event):
self.cursor.setText('Mouse coords: ( %d : %d )' % (event.x(), event.y()))

Finnally this is the way I made it :
class ImLabel(QLabel):
def __init__(self):
super().__init__()
def mouseMoveEvent(self, event):
super(ImLabel, self).mouseMoveEvent(event)
self.x,self.y = event.x(),event.y()
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
...
def mouseMoveEvent(self,event):
self.cursor.setText('Mouse coords: ( %d : %d )' % (self.source_image.x,self.source_image.y))

Related

How to let sibling windows accept event?

I write a simple window, when cursor in QLineEdit and press Enter Key, I want the QGraphicsRectItem, QGraphicsScene, QGraphicsView and QWidget also accept QKeyEvent or MyEvent(customize event).I have no idea to do it,Could someone have good method to do this?
Code Sample
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
class MyEvent(QEvent):
Type = QEvent.registerEventType()
def __init__(self):
super().__init__(MyEvent.Type)
self._data = "test"
class Item(QGraphicsRectItem):
def __init__(self):
super().__init__()
self.setRect(0 ,0, 100, 100)
self.setBrush(Qt.red)
self.setFlags(QGraphicsItem.ItemIsFocusable)
def keyPressEvent(self, event: QKeyEvent) -> None:
print("Item KeyPress", event.key())
return super().keyPressEvent(event)
class Scene(QGraphicsScene):
def keyPressEvent(self, event: QKeyEvent) -> None:
print("Scene KeyPress", event.key())
return super().keyPressEvent(event)
class View(QGraphicsView):
def keyPressEvent(self, event: QKeyEvent) -> None:
print("View KeyPress", "do something work here", event.key())
return super().keyPressEvent(event)
class MainWindow(QWidget):
def __init__(self):
super().__init__()
lay = QVBoxLayout()
view = View()
scene = Scene()
scene.addItem(Item())
view.setScene(scene)
lay.addWidget(view)
lay.addWidget(QLineEdit("Cursor In here, post Enter Event to QGraphicsView"))
self.setLayout(lay)
self.show()
self.view = view
def keyPressEvent(self, e: QKeyEvent) -> None:
print("QWidget KeyPress", e.key())
# myEvent = MyEvent()
# QApplication.postEvent(myEvent)
return super().keyPressEvent(e)
app = QApplication([])
m = MainWindow()
app.exec()
How let others item also get the event?

position of super().__init__() gives different output

I was trying to understand this example working.
class P:
def __init__(self):
self.__x=100
self.y=200
def print(self):
print(self.__x, self.y)
class C(P):
def __init__(self):
super().__init__() <-------------------
self.__x=300
self.y=400
d = C()
d.print()
output: 100 400
class P:
def __init__(self):
self.__x=100
self.y=200
def print(self):
print(self.__x, self.y)
class C(P):
def __init__(self):
self.__x=300
self.y=400
super().__init__() <--------------------
d = C()
d.print()
output: 100 200
Can someone explain the execution flow of the above codes leading to separate outputs?

How to shift position of radio button and reverse radio button function when unchecking it?

I would like to ask 2 questions about my code. First, how do I shift the position of my radio button into the position that I want (I wrote it in the code)? And how do I reverse my LCD screen after unchecking it? Right now, it shows '02' when checked but I want to reverse the process when I uncheck it. Any solution?
class MyRadioButton(QtGui.QRadioButton):
def __init__(self):
super(MyRadioButton, self).__init__()
self.value = None
def SetValue(self, val):
self.value = val
def GetValue(self):
return self.value
class UserTool(QtGui.QDialog):
def __init__(self, parent = None):
super(UserTool, self).__init__()
self.layout = QtGui.QVBoxLayout(self)
self.setup(self)
def setup(self, Dialog):
Dialog.setObjectName(_fromUtf8("Dialog"))
self.resize(688, 677)
self.lcdNumber = QtGui.QLCDNumber(Dialog)
self.lcdNumber.setGeometry(QtCore.QRect(590, 10, 71, 23))
self.lcdNumber.setFrameShadow(QtGui.QFrame.Raised)
self.lcdNumber.setObjectName(_fromUtf8("lcdNumber"))
self.lcdNumber.setStyleSheet("* {background-color: black; color: white;}")
self.lcdNumber.display("00")
self.radioButton_8 = MyRadioButton()
self.radioButton_8.setText("A1")
self.radioButton_8.SetValue("02")
self.radioButton_8.toggled.connect(self.showValueFromRadioButtonToLCDNumber)
self.layout.addWidget(self.radioButton_8)
#self.radioButton_8 = QtGui.QRadioButton(Dialog)
self.radioButton_8.setGeometry(QtCore.QRect(460, 10, 82, 17))
self.radioButton_8.setChecked(False)
self.radioButton_8.setAutoExclusive(False)
self.radioButton_8.setObjectName(_fromUtf8("radioButton_8"))
def retranslateUi(self, Dialog):
self.radioButton_8.setText(_translate("Dialog", "A1", None))
def showValueFromRadioButtonToLCDNumber(self):
value = self.radioButton_8.GetValue()
if self.radioButton_8.isChecked():
self.lcdNumber.display(value)
Here is working example. In order to show previous value you need mechanism to cash that value before it is changed. To shift radioButton I use addSpacing()
# -*- coding: utf-8 -*-
import sys
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import Qt
class MyRadioButton(QtGui.QRadioButton):
def __init__(self):
super(MyRadioButton, self).__init__()
self.value = None
def SetValue(self, val):
self.value = val
def GetValue(self):
return self.value
class Widget(QtGui.QWidget):
def __init__(self):
super(Widget, self).__init__()
self.layout = QtGui.QVBoxLayout(self)
self.radioButton = MyRadioButton()
self.radioButton.setText("some text")
self.radioButton.SetValue("02")
self.radioButton.toggled.connect(self.showValueFromRadioButtonToLCDNumber)
self.lcdNumber = QtGui.QLCDNumber()
self.lcdNumber.display("-2")# previous value
self.layoutHorizontal = QtGui.QHBoxLayout(self)
self.layoutHorizontal.addSpacing(20)# add space before radioButton
self.layoutHorizontal.addWidget(self.radioButton)
self.layout.addLayout(self.layoutHorizontal)
self.layout.addWidget(self.lcdNumber)
self.previousValue = ""
def showValueFromRadioButtonToLCDNumber(self):
value = self.radioButton.GetValue()
if self.radioButton.isChecked():
self.previousValue = self.lcdNumber.value()# save previous value before it is changed
self.lcdNumber.display(value)
else:
self.lcdNumber.display(self.previousValue)

QThread workaround in a Basic GUI

Here is the sample code
import sys, time
from PyQt4 import QtCore, QtGui
class MyApp(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setGeometry(300, 300, 280, 600)
self.setWindowTitle('threads')
self.layout = QtGui.QVBoxLayout(self)
self.testButton = QtGui.QPushButton("test")
self.connect(self.testButton, QtCore.SIGNAL("released()"), self.test)
self.listwidget = QtGui.QListWidget(self)
self.layout.addWidget(self.testButton)
self.layout.addWidget(self.listwidget)
def add(self, text):
print "Add: ", text
self.listwidget.addItems(text)
self.listwidget.sortItems()
# def addBatch(self, text="test", iters=6, delay=0.3):
# for i in range(iters):
# time.sleep(delay)
# self.add(text + " " + str(i))
def test(self):
self.listwidget.clear()
#self.addBatch("_non_thread", iters=6, delay=0.3)
self.workThread = WorkThread()
self.connect(self.workThread, QtCore.SIGNAL("update(QString"), self.add)
self.workThread.start()
class WorkThread(QtCore.QThread):
def __init__(self):
QtCore.QThread.__init__(self)
def __del__(self):
self.wait()
def run(self):
for i in range(6):
time.sleep(0.3)
self.emit(QtCore.SIGNAL('update(QString'), "from work thread " + str(i))
return
app = QtGui.QApplication(sys.argv)
test = MyApp()
test.show()
app.exec_()
Here I have a basic GUI with a listwidget and a push button. When I press the push button, I program should wait a moment and display a string in that listwidget. The WorkThread class does the waiting stuff and after waiting it emits a signal. But when I run the program, only I can see the GUI and nothing is displayed in the listwidget.
Can somebody tell me what is the reason behind this and how to fix this ?
QListWidget.addItems expects a list of items but you're giving it a single QString. You should use .addItem.
There are also a few minor corrections. You don't need to implement __del__ in your thread. You can skip __init__ if you're not doing additional stuff. And you should use new style signals and connections.
Here is the result with all corrections:
import sys, time
from PyQt4 import QtCore, QtGui
class MyApp(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setGeometry(300, 300, 280, 600)
self.setWindowTitle('threads')
self.layout = QtGui.QVBoxLayout(self)
self.testButton = QtGui.QPushButton("test")
self.testButton.clicked.connect(self.test)
self.listwidget = QtGui.QListWidget(self)
self.layout.addWidget(self.testButton)
self.layout.addWidget(self.listwidget)
def add(self, text):
print "Add: ", type(text)
self.listwidget.addItem(text)
self.listwidget.sortItems()
# def addBatch(self, text="test", iters=6, delay=0.3):
# for i in range(iters):
# time.sleep(delay)
# self.add(text + " " + str(i))
def test(self):
self.listwidget.clear()
#self.addBatch("_non_thread", iters=6, delay=0.3)
self.workThread = WorkThread()
self.workThread.update.connect(self.add)
self.workThread.start()
class WorkThread(QtCore.QThread):
update = QtCore.pyqtSignal(str)
def run(self):
for i in range(6):
time.sleep(0.3)
self.update.emit("from work thread " + str(i))
app = QtGui.QApplication(sys.argv)
test = MyApp()
test.show()
sys.exit(app.exec_())
The PyQtWiki contains a pretty elaborate example how to send signals from a background thread to the UI. Apparently, no special magic is necessary as long as you QThread to implement your thread.
But I noticed that you use the signal released() to connect the button with the method test(). Did you try clicked()?

How to debug pyqt signal/slot connections, probably threading issue

I have the following piece of example code of my problem. Running this, I would expect that (if you type something in the lineedit) the A.updateValue slot would be called twice and thus show 'a.updatevalue called' and 'a2.updatevalue called'
However, it is only called once, namely for the self.a2 object and not for the self.a object, the latter which is sent from a worker thread to the GUI thread. How can I fix this so that this piece of code also triggers the slot for the self.a object?
Thank you,
David
import os, sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class A(QObject):
def __init__(self, name):
QObject.__init__(self)
self.name = name
def updateValue(self, value):
print(self.name + ".updatevalue called")
class workerthread(QThread):
def __init__(self, parent=None):
QThread.__init__(self, parent)
def run(self):
a = A('a')
QObject.emit(self, SIGNAL("mySignal"), a)
class Main(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.centralwidget = QWidget(self)
self.hbox = QHBoxLayout()
self.centralwidget.setLayout(self.hbox)
def update(self, a):
self.a = a
edit = QLineEdit("", self)
self.hbox.addWidget(edit)
edit.textChanged.connect(self.a.updateValue)
self.a2 = A('a2')
edit.textChanged.connect(self.a2.updateValue)
if __name__ == "__main__":
app = QApplication(sys.argv)
gui = Main()
worker = workerthread()
worker.connect(worker, SIGNAL('mySignal'), gui.update)
worker.start()
gui.show()
sys.exit(app.exec_())
Define a when you initialize workerThread
class workerthread(QThread):
def __init__(self, parent=None):
QThread.__init__(self, parent)
self.a = A('a')
def run(self):
QObject.emit(self, SIGNAL("mySignal"), self.a)

Resources