What am I doing wrong here? I expect that "image1.jpg" is shown over "image.jpg" ,at position where I've clicked, but it does not. Here is my code (image1.jpg is 10 times smaller then image.jpg):
import sys
from PyQt4 import QtGui, QtCore
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class DrawImage(QMainWindow):
def __init__(self, parent=None):
super(QMainWindow, self).__init__(parent)
self.setWindowTitle('Select Window')
self.local_image = QImage('image.JPG')
self.local_grview = QGraphicsView()
self.setCentralWidget( self.local_grview )
self.local_scene = QGraphicsScene()
self.image_format = self.local_image.format()
self.pixMapItem = QGraphicsPixmapItem(QPixmap(self.local_image), None, self.local_scene)
self.pixMapItem.setZValue(10.0)
self.local_grview.setScene( self.local_scene )
self.pixMapItem.mousePressEvent = self.pixelSelect
def pixelSelect( self, event ):
position = QPoint( event.pos().x(), event.pos().y())
local_image = QImage('image1.JPG')
pixMapItem = QGraphicsPixmapItem(QPixmap(local_image), self.pixMapItem, self.local_scene)
pixMapItem.setZValue(100.0)
pixMapItem.setPos(position.x(), position.y());
print position, self.pixMapItem.zValue(), pixMapItem.zValue()
def main():
app = QtGui.QApplication(sys.argv)
form = DrawImage()
form.show()
app.exec_()
if __name__ == '__main__':
main()
Edit 1 I've tried self.local_grview.setUpdatesEnabled(True) and updating scene at the end of pixelSelect method: self.local_grview.update() , nothing changed
Your code looks correct and works as expected for me ie. the second smaller image displays over the first.
Have you tried displaying just the second image? Perhaps you have an incorrect path which is causing your second image not to show.
Related
In my QMainWindow i have a button which opens a new QDialog in the bottom right monitorcorner with a successmessage when i click it.
Now, if i move the QMainWindow to another monitor (i have 3 monitor) and click the button the successmessage popup appears in the monitor where the QMainWindow was opened. What i want is that the popup message appears in the monitor where my QMainWindow actually is. So if i move the QMainWindow to Monitor 1 and click the button, the successpopup should opens in monitor 1. If the QMainWindow is in monitor 2, the successpopup should open in monitor 2 an same for monitor 3.
with
screenNumber = QDesktopWidget().screenNumber(self)
i can read the screennumber where the mainwindow is. and this works fine. Evertime i click the button i read out the screennumber. But i don't found a way, to set the screennumber to my notification.
Any ideas?
Edit:
maybe it helps if i show my notify class
notes.py
from UIs.UI_notify import Ui_Notification
from PyQt5.QtWidgets import QDialog, QApplication, QDesktopWidget
from PyQt5 import QtCore
from PyQt5.QtCore import QRect, QPropertyAnimation, QTimer
import sys
class icon():
checked = "check-circle"
alert = "times-circle"
question = "question-circle"
class notify(QDialog, Ui_Notification):
def __init__(self, parent=None):
super(notify,self).__init__(parent)
self.setupUi(self)
self.setWindowFlag(QtCore.Qt.WindowType.FramelessWindowHint)
self.setAttribute(QtCore.Qt.WidgetAttribute.WA_TranslucentBackground)
## Some helping stuff
############################################################
parent_sSize = QDesktopWidget().screenGeometry(parent)
parent_screenNumber = QDesktopWidget().screenNumber(parent)
sSize = QDesktopWidget().screenGeometry()
screenNumber = QDesktopWidget().screenNumber()
print("notification ScreenNumber = " + str(screenNumber))
print(sSize.width())
print(sSize.height())
print("Parents ScreenNumber = " + str(parent_screenNumber))
print(parent_sSize.width())
print(parent_sSize.height())
self.Note_Exit.clicked.connect(self.close)
## ScreenSize from parent
############################################################
self.hidedPos = QRect(parent_sSize.width()-self.width()-10,
parent_sSize.height()-self.height()+200,
self.frameGeometry().width(),
self.frameGeometry().height())
self.showPos = QRect(parent_sSize.width()-self.width()-10,
parent_sSize.height()-self.height()-50,
self.frameGeometry().width(),
self.frameGeometry().height())
def setNote(self, icon=icon.checked, headline="Headline", text="Text"):
self.icon = icon
self.headline = headline
self.text = text
self.noty_Label_Icon.setText(self.icon)
self.noty_Label_Headline.setText(self.headline)
self.noty_Label_Text.setText(self.text)
self.setGeometry(self.hidedPos)
self.anim = QPropertyAnimation(self,b"geometry")
self.anim.setDuration(700)
self.anim.setEasingCurve(QtCore.QEasingCurve.OutBack)
self.anim.setEndValue(self.showPos)
self.anim.start()
self.notyTimer = QTimer()
self.notyTimer.singleShot(4000,self.hideNote)
def hideNote(self):
self.anim = QPropertyAnimation(self,b"geometry")
self.anim.setDuration(700)
self.anim.setEasingCurve(QtCore.QEasingCurve.InOutBack)
self.anim.setEndValue(self.hidedPos)
self.anim.start()
self.anim.finished.connect(self.close)
if __name__ == "__main__":
notes = QApplication(sys.argv)
dialog = notify()
dialog.show()
sys.exit(notes.exec())
You cannot use the size of the widget during its construction, as at that moment it has a default size (640x480 for top level widgets, 100x30 for widgets created with a parent, including dialogs): the only reliable option is to use the sizeHint() or ensure that the layout has been properly activated with adjustSize().
Then, you don't need the screen to get the target position, as the parent geometry will suffice, but you do need it for the start position, otherwise the dialog will "pop up" at an arbitrary point below the window. Note that QDesktopWidget is considered obsolete, and you should use QScreen instead.
Finally, since you might want to reuse the notification, the start position should be set when the popup is actually being shown, not before. The same goes for the position when hiding (in case the notification could be moved).
class Notify(QDialog, Ui_Notification):
def __init__(self, parent):
super().__init__(parent)
self.setupUi(self)
self.setWindowFlag(QtCore.Qt.WindowType.FramelessWindowHint)
self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
self.showAnim = QPropertyAnimation(self, b'geometry')
self.showAnim.setDuration(700)
self.showAnim.setEasingCurve(QtCore.QEasingCurve.OutBack)
self.hideAnim = QPropertyAnimation(self, b'geometry')
self.hideAnim.setDuration(700)
self.hideAnim.setEasingCurve(QtCore.QEasingCurve.InOutBack)
self.hideTimer = QTimer(self, singleShot=True)
self.hideTimer.setInterval(4000)
self.hideTimer.timeout.connect(self.hideNote)
self.showAnim.finished.connect(self.hideTimer.start)
self.hideAnim.finished.connect(self.close)
def setNote(self, icon=icon.checked, headline="Headline", text="Text"):
self.icon = icon
self.headline = headline
self.text = text
self.noty_Label_Icon.setText(self.icon)
self.noty_Label_Headline.setText(self.headline)
self.noty_Label_Text.setText(self.text)
self.adjustSize() # important!
endRect = self.rect()
center = self.parent().geometry().center()
endRect.moveCenter(center)
screen = QApplication.screenAt(center)
startRect = QRect(endRect)
startRect.moveTop(screen.geometry().bottom())
self.setGeometry(startRect)
self.showAnim.setStartValue(startRect)
self.showAnim.setEndValue(endRect)
self.showAnim.start()
self.show()
def hideNote(self):
rect = self.geometry()
self.hideAnim.setStartValue(rect)
screen = QApplication.screenAt(rect.center())
rect.moveTop(screen.geometry().bottom())
self.hideAnim.setEndValue(rect)
self.hideAnim.start()
if __name__ == "__main__":
notes = QApplication(sys.argv)
notes.setStyle('fusion')
w = QMainWindow()
b = QPushButton('click!')
w.setCentralWidget(b)
w.show()
notify = Notify(w)
b.clicked.connect(lambda: notify.setNote())
sys.exit(notes.exec())
Be aware that if you're going to create the popup every time, you should also set the WA_DeleteOnClose attribute in order to destroy it when closed, otherwise it will be kept in memory.
Note: QTimer.singleShot() is a static function, creating an instance of QTimer to use it is pointless, as that instance won't be used and a new QTimer would be created anyway.
Thank you.
In the meantime i found a solution which works for me.
Look a little dirty but works.
could you tell me, whats the difference between my code an yours?
Why should i use your code, except the fact that you are a better programmer ;-)
I set the WA_DeleteOnClose Attribute.
Good to know that. Thanks
notes.py
from UIs.UI_notify import Ui_Notification
from PyQt5.QtWidgets import QDialog, QApplication
from PyQt5 import QtCore
from PyQt5.QtCore import QRect, QPropertyAnimation, QTimer
import sys
class icon():
checked = "check-circle"
alert = "times-circle"
question = "question-circle"
clock = "clock"
class notify(QDialog, Ui_Notification):
def __init__(self, parent=None):
super(notify,self).__init__(parent)
self.setupUi(self)
self.setWindowFlag(QtCore.Qt.WindowType.FramelessWindowHint)
self.setAttribute(QtCore.Qt.WidgetAttribute.WA_TranslucentBackground)
self.setAttribute(QtCore.Qt.WidgetAttribute.WA_DeleteOnClose)
self.setWindowModality(QtCore.Qt.NonModal)
self.Note_Exit.clicked.connect(self.close)
self.parent_h = self.parent().geometry().height()
self.parent_w = self.parent().geometry().width()
self.parent_x = self.parent().geometry().x()
self.parent_y = self.parent().geometry().y()
self.dialog_w = self.width()
self.dialog_h = self.height()
self.setGeometry(self.parent_x+self.parent_w-self.dialog_w-10, self.parent_y+self.parent_h-self.dialog_h+120, self.dialog_w, self.dialog_h)
## ScreenSize from parent
############################################################
def setNote(self, icon=icon.checked, headline="Headline", text="Text"):
self.icon = icon
self.headline = headline
self.text = text
self.noty_Label_Icon.setText(self.icon)
self.noty_Label_Headline.setText(self.headline)
self.noty_Label_Text.setText(self.text)
self.anim = QPropertyAnimation(self,b"geometry")
self.anim.setDuration(700)
self.anim.setEasingCurve(QtCore.QEasingCurve.OutBack)
self.anim.setEndValue(QRect(self.parent_x+self.parent_w-self.dialog_w-10, self.parent_y+self.parent_h-self.dialog_h-20, self.dialog_w, self.dialog_h))
self.anim.start()
self.notyTimer = QTimer()
self.notyTimer.singleShot(4000,self.hideNote)
def hideNote(self):
self.anim = QPropertyAnimation(self,b"geometry")
self.anim.setDuration(700)
self.anim.setEasingCurve(QtCore.QEasingCurve.InOutBack)
self.anim.setEndValue(QRect(self.parent_x+self.parent_w-self.dialog_w-10, self.parent_y+self.parent_h-self.dialog_h+120, self.dialog_w, self.dialog_h))
self.anim.start()
self.anim.finished.connect(self.close)
if __name__ == "__main__":
notes = QApplication(sys.argv)
dialog = notify()
dialog.show()
sys.exit(notes.exec())
I made a QGraphicsTextItem and set plain text as its content. After that, I set the QGraphicsTextItem inside the QGraphicsWidget.
My question is, Is it possible to resize the QGraphicsTextItem including its text/contents like in this picture:
This is the video of the resizing that I'm asking for.
If this is possible, how can I apply it to the QGraphicsTextItem?
The first picture is the image of the QGraphicsTextItem but I have no idea how to implement the resizing in the video.
Things I've tried:
I tried using the setTextWidth() and setting it to 0.5 but it's not working.
I also tried using adjustSize() to the QGraphicsTextItem but it's also not working.
Code to reproduce the issue:
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.view = QGraphicsView()
scene = QGraphicsScene()
#before resizing
item = QGraphicsTextItem("Line 1 Line 2 Line 3")
item.setFlags(QGraphicsWidget.ItemIsSelectable)
item.setPos(self.view.mapToScene(2, 2))
scene.addItem(item)
#after resizing
item_1 = QGraphicsTextItem("Line 1\nLine 2\nLine 3")
item_1.setFlags(QGraphicsWidget.ItemIsSelectable)
item_1.setPos(self.view.mapToScene(2, 30))
scene.addItem(item_1)
self.view.setScene(scene)
self.setCentralWidget(self.view)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MainWindow()
w.show()
app.exec_()
working on simple GUI project. I've got some code from online,and found out how to connect the IP-webcam app, but the question is how do I use this code in my PyQt4 GUI so that the visual of the camera will be shown in the scroll-area widget.
This is the code i used:
import urllib
import cv2
import numpy as np
url='http://192.168.0.100:8080/shot.jpg'
while True:
imgResp=urllib.urlopen(url)
imgNp=np.array(bytearray(imgResp.read()),dtype=np.uint8)
img=cv2.imdecode(imgNp,-1)
# all the opencv processing is done here
cv2.imshow('test',img)
if ord('q')==cv2.waitKey(10):
exit(0)
As #furas points out, a possible option is to use numpy and cv2 to convert it to QPixmap and display it in a QLabel, and so that it looks like streaming run it in a loop.
But instead of getting complicated with all of the above, the simplest thing is to use QtNetwork to get the bytes and convert it directly to QPixmap and send it through signals:
from PyQt4 import QtCore, QtGui, QtNetwork
class IPWebcam(QtCore.QObject):
pixmapChanged = QtCore.pyqtSignal(QtGui.QPixmap)
def __init__(self, url, parent=None):
super(IPWebcam, self).__init__(parent)
self._url = url
self.m_manager = QtNetwork.QNetworkAccessManager(self)
self.m_manager.finished.connect(self._on_finished)
self.m_stopped = True
def start(self):
self.m_stopped = False
self._launch_request()
def stop(self):
self.m_stopped = True
def _launch_request(self):
request = QtNetwork.QNetworkRequest(QtCore.QUrl(self._url))
self.m_manager.get(request)
#QtCore.pyqtSlot(QtNetwork.QNetworkReply)
def _on_finished(self, reply):
ba = reply.readAll()
pixmap = QtGui.QPixmap()
if pixmap.loadFromData(ba):
self.pixmapChanged.emit(pixmap)
if not self.m_stopped:
self._launch_request()
class Widget(QtGui.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
self.m_label = QtGui.QLabel()
self.m_button = QtGui.QPushButton(
"Start", clicked=self.onClicked, checkable=True
)
lay = QtGui.QVBoxLayout(self)
lay.addWidget(self.m_label)
lay.addWidget(self.m_button)
self.resize(640, 480)
url = "http://192.168.0.100:8080/shot.jpg"
self.m_webcam = IPWebcam(url, self)
self.m_webcam.pixmapChanged.connect(self.m_label.setPixmap)
#QtCore.pyqtSlot(bool)
def onClicked(self, checked):
if checked:
self.m_button.setText("Stop")
self.m_webcam.start()
else:
self.m_button.setText("Start")
self.m_webcam.stop()
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
I have a window that has six symmetrically placed labels, all showing images (designed using qt-designer with the help of layouts). I would like to resize these images according to the changing window size. I have found some help in previous questions like: PyQt: Detect resizing in Widget-window resized signal
At present, using resizeEvent() in my case does not shrink the images according to the resize function. It is already triggered with the display of my form window thereby making the pushButton useless. Above all, the resulting execution is very slow. My images are of 2058x1536 dimension and displayed transparently.
My qt-designer code is given here: https://pastebin.com/TzM6qiKZ
import Ui_ImageCrop_Test
import sys
from PyQt5.QtWidgets import QMainWindow, QApplication
from PyQt5.QtGui import QPixmap, QImage, QPainter, QColor
from PyQt5.QtCore import Qt
class ImageCrop(Ui_ImageCrop_Test.Ui_MainWindow, QMainWindow):
def __init__(self, parent=None):
super(ImageCrop, self).__init__()
self.setupUi(self)
self.transparency = 220
with open("Img_files.txt") as file:
self.img_files = file.read().splitlines()
self.length = len(self.img_files)
self.pushButton_1.clicked.connect(self.click1)
self.label_1.resizeEvent = self.click1
def click1(self, event):
for i in range(6):
image = QImage(self.img_files[i])
image = image.convertToFormat(QImage.Format_ARGB8565_Premultiplied)
p = QPainter(image)
p.setCompositionMode(QPainter.CompositionMode_DestinationIn)
p.fillRect(image.rect(), QColor(0, 0, 0, self.transparency))
p.end()
pixmap = QPixmap(image)
w = int(self.label_1.width() - 4.0)
h = int(self.label_1.height() - 4.0)
smaller_pixmap = pixmap.scaled(w, h, Qt.IgnoreAspectRatio, Qt.FastTransformation)
if i == 0:
self.label_1.setPixmap(smaller_pixmap)
if i == 1:
self.label_2.setPixmap(smaller_pixmap)
if i == 2:
self.label_3.setPixmap(smaller_pixmap)
if i == 3:
self.label_4.setPixmap(smaller_pixmap)
if i == 4:
self.label_5.setPixmap(smaller_pixmap)
if i == 5:
self.label_6.setPixmap(smaller_pixmap)
def main():
app = QApplication(sys.argv)
form1 = ImageCrop()
form1.show()
app.exec_()
if __name__ == '__main__': main()
Is there any solution to run this code faster? For example, I was thinking to make all my labels turn blank during a mouse click at the edge of my window and then images reappear after the mouse button is released. This does not seem so neat. Also, I am not sure if using paintEvent can reduce my lag. Thank you for your suggestions and comments.
QLabel has the scaledContents property that allows the image to scale automatically:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
import Ui_ImageCrop_Test
class ImageCrop(QtWidgets.QMainWindow, Ui_ImageCrop_Test.Ui_MainWindow):
def __init__(self, parent=None):
super(ImageCrop, self).__init__()
self.setupUi(self)
self.pushButton_1.clicked.connect(self.click1)
self.transparency = 220
with open("Img_files.txt") as file:
self.img_files = file.read().splitlines()
#QtCore.pyqtSlot()
def click1(self):
labels = [self.label_1, self.label_2, self.label_3,
self.label_4, self.label_5, self.label_6]
for label, filename in zip(labels, self.img_files):
image = QtGui.QImage(filename)
image = image.convertToFormat(QtGui.QImage.Format_ARGB8565_Premultiplied)
p = QtGui.QPainter(image)
p.setCompositionMode(QtGui.QPainter.CompositionMode_DestinationIn)
p.fillRect(image.rect(), QtGui.QColor(0, 0, 0, self.transparency))
p.end()
pixmap = QtGui.QPixmap(image)
w = int(label.width() - 4.0)
h = int(label.height() - 4.0)
smaller_pixmap = pixmap.scaled(w, h, QtCore.Qt.IgnoreAspectRatio, QtCore.Qt.FastTransformation)
label.setPixmap(smaller_pixmap)
label.setScaledContents(True)
def main():
app = QtWidgets.QApplication(sys.argv)
form1 = ImageCrop()
form1.show()
app.exec_()
if __name__ == '__main__': main()
I have this sample of code:
import sys
import time
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class Bar(QDialog):
def __init__(self, parent=None):
super(Bar, self).__init__()
self.pbar = QProgressBar(self)
self.pbar.setValue(0)
layout = QHBoxLayout()
layout.addWidget(self.pbar)
self.setLayout(layout)
def main(self):
for value in range(1, 100):
time.sleep(1)
print value
self.pbar.setValue(value)
app = QApplication(sys.argv)
form = Bar()
form.show()
form.main()
app.exec_()
I expect progressbar's value to increased by 1 every second.
Instead, although that all values printed on the screen, the progressbar shows only some of them. Also, the bar appears just when value == 5. I know how to achieve the appropriate result with QBasicTimer(), but why this one does not work? Did i make a stupid mistake?
Try adding a
QApplication.processEvents()
just after print value (this should force the UI to update).