FramelessWindowHint & WindowStaysOnTopHint won't work - python

I want my PyQt5 program to be frameless and always be on top of the screen. When I use the WindowStayOnTopHint it works fine, but when I use it with the FramelessWindowHint it becomes frameless, but does not stay on top of the screen. After doing some research I found this, and it said to try to use setMask, but I could not get it to work.
Here is my code:
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont
from PyQt5.QtWidgets import QApplication, QLabel
class Invisible(QLabel):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.__press_pos = None
self.initUI()
def initUI(self):
self.setWindowFlags(Qt.WindowStaysOnTopHint)
self.setMask() #This is where I use the setMask function, but it raises an error
self.setAttribute(Qt.WA_TranslucentBackground)
self.setText("Drag me...")
self.setFont(QFont("Times", 50, QFont.Bold))
self.adjustSize()
self.move(QApplication.instance().desktop().screen().rect().center()
- self.rect().center())
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.__press_pos = event.pos()
def mouseReleaseEvent(self, event):
if event.button() == Qt.LeftButton:
self.__press_pos = None
def mouseMoveEvent(self, event):
if self.__press_pos:
self.move(self.pos() + (event.pos() - self.__press_pos))
def main():
app = QApplication(sys.argv)
w = Invisible()
w.show()
return app.exec_()
if __name__ == '__main__':
sys.exit(main())
This code gives me the error:
TypeError: arguments did not match any overloaded call:
setMask(self, QBitmap): not enough arguments
setMask(self, QRegion): not enough arguments
It is asking for more arguments, but when I give it more arguments it says that there are too many arguments.
How do I fix this?

The problem in your case is that you must activate both properties with the operator |
self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint)
Complete code:
import sys
from PyQt5.QtCore import Qt, QPoint
from PyQt5.QtGui import QFont
from PyQt5.QtWidgets import QApplication, QLabel, QStyle
class Invisible(QLabel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.__press_pos = QPoint()
self.initUI()
def initUI(self):
self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint)
self.setAttribute(Qt.WA_TranslucentBackground)
self.setText("Drag me...")
self.setFont(QFont("Times", 50, QFont.Bold))
self.adjustSize()
self.setGeometry(
QStyle.alignedRect(
Qt.LeftToRight,
Qt.AlignCenter,
self.size(),
QApplication.instance().desktop().availableGeometry()
)
)
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.__press_pos = event.pos()
def mouseReleaseEvent(self, event):
if event.button() == Qt.LeftButton:
self.__press_pos = QPoint()
def mouseMoveEvent(self, event):
if not self.__press_pos.isNull():
self.move(self.pos() + (event.pos() - self.__press_pos))
def main():
app = QApplication(sys.argv)
w = Invisible()
w.show()
return app.exec_()
if __name__ == '__main__':
sys.exit(main())
setMask() serves to give a different border to the widget, for example for an example I got the following:

Related

How to draw polyline with PyQt5 in Python?

I want to draw polyline with mouse event. But I can't set endpoints by clicking, or choose pen type. I want to draw linear lines, but when i write this code it only shows dots instead of drawing a line. Here is my code:
import sys
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtGui import QPainter, QBrush, QColor, QPen, QPainterPath
from PyQt5.QtWidgets import QLabel, QGraphicsScene, QGraphicsView
class MyWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.begin = QtCore.QPoint()
self.end = QtCore.QPoint()
self.beginList = []
self.endList = []
self.initUI()
def initUI(self):
self.setGeometry(200, 200, 1000, 500)
self.label = QLabel(self)
self.label.resize(500, 40)
self.show()
def paintEvent(self, event):
qp = QPainter(self)
for i,j in zip(self.beginList, self.endList):
qp.drawLines(QtCore.QLineF(i,j))
def mouseMoveEvent(self, event):
self.begin = event.pos()
self.end = event.pos()
self.beginList.append(self.begin)
self.endList.append(self.end)
self.label.setText('Coordinates: ( %d : %d )' % (event.x(), event.y()))
self.update()
def mouseReleaseEvent(self, event):
self.begin = event.pos()
self.end = event.pos()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = MyWidget()
window.resize(800,600)
sys.exit(app.exec_())
If the OP code is analyzed, the starting point and the end point coincide, so when drawing a line between 2 points of the same location, only one point will be drawn. The logic is to join the point obtained in the i-th step with the (i+1)-th point.
To do the above the simplest thing is to use a QPainterPath:
import sys
from PyQt5 import QtWidgets, QtGui, QtCore
class MyWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.initUI()
self.paths = []
def initUI(self):
self.setGeometry(200, 200, 1000, 500)
self.label = QtWidgets.QLabel(self)
self.show()
def paintEvent(self, event):
qp = QtGui.QPainter(self)
for path in self.paths:
qp.drawPath(path)
def mousePressEvent(self, event):
path = QtGui.QPainterPath()
path.moveTo(event.pos())
self.paths.append(path)
super().mousePressEvent(event)
def mouseMoveEvent(self, event):
self.paths[-1].lineTo(event.pos())
self.label.setText('Coordinates: ( %d : %d )' % (event.x(), event.y()))
self.label.adjustSize()
self.update()
super().mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
self.paths[-1].lineTo(event.pos())
self.update()
super().mouseReleaseEvent(event)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = MyWidget()
window.resize(800, 600)
sys.exit(app.exec_())

Drag and Drop QLabels with PyQt5

I'm trying to drag and drop a Qlabel on another Qlabel with PyQt5:
from PyQt5.QtWidgets import QApplication, QWidget, QToolTip, QPushButton, QMessageBox, QHBoxLayout, QVBoxLayout, QGridLayout,QFrame, QComboBox, QLabel, QLineEdit
from PyQt5.QtGui import QIcon, QFont, QPixmap, QImage
import sys
class my_label(QLabel):
def __init__(self,title,parent):
super().__init__(title,parent)
self.setAcceptDrops(True)
def dragEnterEvent(self,event):
if event.mimeData().hasFormat("text/plain"):
event.accept()
else:
event.ignore()
def dropEvent(self,event):
self.setText(event.mimeData().text())
class application(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
label = my_label("drop there",self)
label.resize(100,100)
label.move(190,65)
label_to_drag = QLabel("drag this",self)
#label_to_drag.setDragEnabled(True) #doesn't work with QLabel
self.show()
def closeEvent(self,event):
message = QMessageBox.question(self,"Message","Quit ?",QMessageBox.Yes | QMessageBox.No,QMessageBox.No)
if message == QMessageBox.Yes:
event.accept()
else:
event.ignore()
app = QApplication(sys.argv)
fenetre = application()
sys.exit(app.exec_())
I wanted to make my first label "draggable",by calling the setDragEnabled(True) method (as i was doing for QLineEdit),and drop it on the second label to change his text. Dropping text from another app is working fine,but I can't find how to drag the QLabel inside my own app...
What did I miss ?
EDIT : modified the code to try to Drag&Drop Images :
class DraggableLabel(QLabel):
def __init__(self,parent,image):
super(QLabel,self).__init__(parent)
self.setPixmap(QPixmap(image))
self.show()
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.drag_start_position = event.pos()
def mouseMoveEvent(self, event):
if not (event.buttons() & Qt.LeftButton):
return
if (event.pos() - self.drag_start_position).manhattanLength() < QApplication.startDragDistance():
return
drag = QDrag(self)
mimedata = QMimeData()
mimedata.setText(self.text())
drag.setMimeData(mimedata)
pixmap = QPixmap(self.size())
painter = QPainter(pixmap)
painter.drawPixmap(self.rect(), self.grab())
painter.end()
drag.setPixmap(pixmap)
drag.setHotSpot(event.pos())
drag.exec_(Qt.CopyAction | Qt.MoveAction)
class my_label(QLabel):
def __init__(self,title,parent):
super().__init__(title,parent)
self.setAcceptDrops(True)
def dragEnterEvent(self,event):
if event.mimeData().hasFormat("text/plain"):
print("event accepted")
event.accept()
else:
print("event rejected")
event.ignore()
def dropEvent(self,event):
if event.mimeData().hasImage():
self.setPixmap(QPixmap.fromImage(QImage(event.mimeData().imageData())))
class application(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
label_to_drag = DraggableLabel(self,"index.jpg")
label = my_label("drop there",self)
label.resize(100,100)
label.move(190,65)
self.show()
When I drop the DraggableLabel (displaying the image) on my_label,the event is accepted, but hasImage() always returns false...Is the way I set the image up wrong ?
In the case of QLabel you must create everything from the beginning, for this you can follow the examples of the docs.
In the following example I have placed an example where one class only accepts the drop and the other the drag so that you can see each part and understand better.
import sys
from PyQt5.QtWidgets import QApplication, QLabel, QWidget
from PyQt5.QtGui import QDrag, QPixmap, QPainter, QCursor
from PyQt5.QtCore import QMimeData, Qt
class DraggableLabel(QLabel):
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.drag_start_position = event.pos()
def mouseMoveEvent(self, event):
if not (event.buttons() & Qt.LeftButton):
return
if (event.pos() - self.drag_start_position).manhattanLength() < QApplication.startDragDistance():
return
drag = QDrag(self)
mimedata = QMimeData()
mimedata.setText(self.text())
drag.setMimeData(mimedata)
pixmap = QPixmap(self.size())
painter = QPainter(pixmap)
painter.drawPixmap(self.rect(), self.grab())
painter.end()
drag.setPixmap(pixmap)
drag.setHotSpot(event.pos())
drag.exec_(Qt.CopyAction | Qt.MoveAction)
class DropLabel(QLabel):
def __init__(self, *args, **kwargs):
QLabel.__init__(self, *args, **kwargs)
self.setAcceptDrops(True)
def dragEnterEvent(self, event):
if event.mimeData().hasText():
event.acceptProposedAction()
def dropEvent(self, event):
pos = event.pos()
text = event.mimeData().text()
self.setText(text)
event.acceptProposedAction()
class Widget(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
label = DropLabel("drop there",self)
label.setGeometry(190, 65, 100,100)
label_to_drag = DraggableLabel("drag this",self)
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
Update:
Do not confuse the QDrag with the QMimeData, if you want to use imageData() you must set it with setImageData() as indicated by the docs:
class DraggableLabel(QLabel):
def __init__(self,parent,image):
super(QLabel,self).__init__(parent)
self.setPixmap(QPixmap(image))
self.show()
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.drag_start_position = event.pos()
def mouseMoveEvent(self, event):
if not (event.buttons() & Qt.LeftButton):
return
if (event.pos() - self.drag_start_position).manhattanLength() < QApplication.startDragDistance():
return
drag = QDrag(self)
mimedata = QMimeData()
mimedata.setText(self.text())
mimedata.setImageData(self.pixmap().toImage())
drag.setMimeData(mimedata)
pixmap = QPixmap(self.size())
painter = QPainter(pixmap)
painter.drawPixmap(self.rect(), self.grab())
painter.end()
drag.setPixmap(pixmap)
drag.setHotSpot(event.pos())
drag.exec_(Qt.CopyAction | Qt.MoveAction)
class my_label(QLabel):
def __init__(self,title,parent):
super().__init__(title,parent)
self.setAcceptDrops(True)
def dragEnterEvent(self,event):
if event.mimeData().hasImage():
print("event accepted")
event.accept()
else:
print("event rejected")
event.ignore()
def dropEvent(self,event):
if event.mimeData().hasImage():
self.setPixmap(QPixmap.fromImage(QImage(event.mimeData().imageData())))

PyQt5: painting using events

I am new on PyQt I am working on a project on which I should implement a feature that make the user able to draw a digit using the mouse (digit recognition system). So what I want is when the mouse button is pressed the app will start to draw till the button is released. I made this source code but it is still not working (I think I am struggling with sending a signal to PaintEvent()).
import sys
from PyQt5 import QtCore
from PyQt5 import QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QWidget, QInputDialog, QLineEdit, QFileDialog,QGraphicsView,QGraphicsScene,QVBoxLayout
from PyQt5.QtWidgets import (QApplication, QLabel, QWidget)
from PyQt5.QtGui import QPainter, QColor, QPen
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPainter
from PyQt5.QtCore import pyqtSignal, QObject
from PyQt5.QtWidgets import QMainWindow, QApplication
class Communicate(QObject):
drawApp = pyqtSignal()
class MyWidget(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setGeometry(300, 300, 300, 220)
self.setWindowTitle('Simple')
self.setMouseTracking(True)
self.label = QLabel(self)
self.label.resize(500, 40)
self.c = Communicate()
self.c.drawApp.connect(self.PaintEvent())
self.show()
def mousePressEvent(self, event):
self.c.drawApp.emit()
self.startingposx = event.x()
self.startingposy = event.y()
#super().mousePressEvent(event)
print ("mouse pressed")
def mouseMoveEvent(self, event):
self.label.setText('Coordinates: ( %d : %d )' % (event.x(), event.y()) )
self.y = event.y()
self.x=event.x()
def PaintEvent(self,event):
qp = QPainter()
qp.begin(self)
#qp.setPen(Qt.red)
qp.drawPoints(self,qp)
qp.end()
self.update()
def mouseReleaseEvent(self,event):
self.endingposx = event.x()
self.endingposy = event.y()
super().mouseReleaseEvent(event)
print("starting point was",self.startingposx)
print("starting point y was ",self.startingposy)
print("ending point was ",self.endingposx)
print("ending point was y ",self.endingposy)
print("released")
def drawPoints(self,qp):
qp.setPen(Qt.red)
size = self.size()
x=self.x
y=self.y
qp.drawPoint(x,y)
app = QApplication(sys.argv)
widget = MyWidget()
widget.show()
app.exec_()
Python is sensitive to uppercase and lowercase so be more careful, the method is called paintEvent.
Also you should not call paintEvent directly, you must use the function update(), this method will internally call paintEvent().
But even correcting that error your problem is not solved, if you want to draw a path it is advisable to use QPainterPath as this stores the strokes.
class Drawer(QWidget):
newPoint = pyqtSignal(QPoint)
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.path = QPainterPath()
def paintEvent(self, event):
painter = QPainter(self)
painter.drawPath(self.path)
def mousePressEvent(self, event):
self.path.moveTo(event.pos())
self.update()
def mouseMoveEvent(self, event):
self.path.lineTo(event.pos())
self.newPoint.emit(event.pos())
self.update()
def sizeHint(self):
return QSize(400, 400)
class MyWidget(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.setLayout(QVBoxLayout())
label = QLabel(self)
drawer = Drawer(self)
drawer.newPoint.connect(lambda p: label.setText('Coordinates: ( %d : %d )' % (p.x(), p.y())))
self.layout().addWidget(label)
self.layout().addWidget(drawer)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MyWidget()
w.show()
sys.exit(app.exec_())
Screenshot:
I don't have the reputation to reply to eyllanesc's solution, but in case others are having issues, the imports were not complete. Here's is eyllanesc's solution with the imports. It will execute without error:
import sys
from PyQt5.QtWidgets import QVBoxLayout
from PyQt5.QtWidgets import (QLabel, QWidget)
from PyQt5.QtGui import QPainter, QPainterPath
from PyQt5.QtCore import pyqtSignal, QPoint, QSize
from PyQt5.QtWidgets import QApplication
class Drawer(QWidget):
newPoint = pyqtSignal(QPoint)
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.path = QPainterPath()
def paintEvent(self, event):
painter = QPainter(self)
painter.drawPath(self.path)
def mousePressEvent(self, event):
self.path.moveTo(event.pos())
self.update()
def mouseMoveEvent(self, event):
self.path.lineTo(event.pos())
self.newPoint.emit(event.pos())
self.update()
def sizeHint(self):
return QSize(400, 400)
class MyWidget(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.setLayout(QVBoxLayout())
label = QLabel(self)
drawer = Drawer(self)
drawer.newPoint.connect(lambda p: label.setText('Coordinates: ( %d : %d )' % (p.x(), p.y())))
self.layout().addWidget(label)
self.layout().addWidget(drawer)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MyWidget()
w.show()
sys.exit(app.exec_())

How to return mouse coordinates in realtime?

I'm new to PyQt and I'm trying to use it to create a widget that returns the position of the mouse in real time.
Here's what I have:
import sys
from PyQt5.QtWidgets import (QWidget, QToolTip,
QPushButton, QApplication)
from PyQt5.QtGui import QFont
class MouseTracker(QWidget):
def __init__(self):
super().__init__()
self.initUI()
self.setMouseTracking(True)
self.installEventFilter(self)
def initUI(self):
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('Mouse Tracker')
self.show()
def eventFilter(self, source, event):
if (event.type() == QtCore.QEvent.MouseMove and
event.buttons() == QtCore.Qt.NoButton):
pos = event.pos()
print('Mouse coords: ( %d : %d )' % (pos.x(), pos.y()))
return QtGui.QWidget.eventFilter(self, source, event)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = MouseTracker()
sys.exit(app.exec_())
I'm confused on how to make this work. I set mouse tracking to True but I'm not sure how to apply the event filter. Any help?
The QMouseEvent function must be implemented since it is executed when the mouse is moved.
import sys
from PyQt5.QtWidgets import (QApplication, QLabel, QWidget)
class MouseTracker(QWidget):
def __init__(self):
super().__init__()
self.initUI()
self.setMouseTracking(True)
def initUI(self):
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('Mouse Tracker')
self.label = QLabel(self)
self.label.resize(200, 40)
self.show()
def mouseMoveEvent(self, event):
self.label.setText('Mouse coords: ( %d : %d )' % (event.x(), event.y()))
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = MouseTracker()
sys.exit(app.exec_())

How to use QRubberBand with QRect Class in PyQt?

I want to select or activate a bunch of buttons by marquee rectangle selection in a UI using QRubberBand and QRect in PyQt.
I would appreciate if anyone could tell me how to implement this functionality?
Here's a simple demo:
from PyQt4 import QtGui, QtCore
class Window(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
layout = QtGui.QVBoxLayout(self)
layout.setMargin(15)
layout.setSpacing(10)
for text in 'One Two Three Four Five'.split():
layout.addWidget(QtGui.QPushButton(text, self))
self.rubberband = QtGui.QRubberBand(
QtGui.QRubberBand.Rectangle, self)
self.setMouseTracking(True)
def mousePressEvent(self, event):
self.origin = event.pos()
self.rubberband.setGeometry(
QtCore.QRect(self.origin, QtCore.QSize()))
self.rubberband.show()
QtGui.QWidget.mousePressEvent(self, event)
def mouseMoveEvent(self, event):
if self.rubberband.isVisible():
self.rubberband.setGeometry(
QtCore.QRect(self.origin, event.pos()).normalized())
QtGui.QWidget.mouseMoveEvent(self, event)
def mouseReleaseEvent(self, event):
if self.rubberband.isVisible():
self.rubberband.hide()
selected = []
rect = self.rubberband.geometry()
for child in self.findChildren(QtGui.QPushButton):
if rect.intersects(child.geometry()):
selected.append(child)
print 'Selection Contains:\n ',
if selected:
print ' '.join(
'Button: %s\n' % child.text() for child in selected)
else:
print ' Nothing\n'
QtGui.QWidget.mouseReleaseEvent(self, event)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())

Categories

Resources