I'm trying to draw an image with a transparent background over the entire screen.
I've done similar with Xlib, but I thought I'd try Qt so my program might work in different environments besides X11.
Before getting committed, I've honestly just searched the internet trying to find a working example but failed.
So I've got an image of coordinates that I want to overlay on the screen.
The image is a PNG with a transparent background.
Here's a picture of what I want to see, my desktop with coordinates:
Here's my PyQt6 code, it draws the image fullscreen but sadly you can't see through it, it has a black background:
import sys
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QImage
from PyQt6.QtWidgets import QApplication, QMainWindow
from PyQt6.QtGui import QPainter
class Img(QMainWindow):
def __init__(self, img_path, parent=None):
super().__init__(parent)
self.qimg = QImage(img_path)
self.setStyleSheet('QMainWindow {background:transparent}')
self.setWindowFlags(
Qt.WindowType.WindowStaysOnTopHint |
Qt.WindowType.FramelessWindowHint |
Qt.WindowType.WindowTransparentForInput
)
self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
def paintEvent(self, qpaint_event):
painter = QPainter(self)
rect = qpaint_event.rect()
painter.drawImage(rect, self.qimg)
self.showFullScreen()
if __name__ == "__main__":
app = QApplication(sys.argv)
img_path = 'coords.png'
window = Img(img_path)
window.show()
sys.exit(app.exec())
Answers don't need to be PyQt6, perhaps PyQt5 or written in Go.
I have tried your code and it works fine, apparently it seems to be a problem of the image, I recommend you to use some kind of external application to erase the transparent parts like this.
Here is a test that works with your code:
If you want to do this automatically I recommend you to use opencv.
Related
I'm coding in PyQt6 and I'd like to add a loading gif to my application. I've got a good quality 256px gif. However, after adding it to app (I used QLabel and QMovie, and added QMovie to QLabel - and I also changed size of the image to 40px using setScaledSize), the quality is much worse. Without scaling the image quality seems to be a bit better, but honestly I don't want to have 256px gif :D
I tried adding 64px and 40px gifs - but the quality was horrible as well.
My code:
from PyQt6.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QLabel
from PyQt6.QtGui import QMovie
from PyQt6.QtCore import QSize
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
layout = QVBoxLayout()
loading = QLabel()
gif = QMovie("loading.gif")
gif.setFormat(b"gif")
gif.setScaledSize(QSize(40,40))
loading.setMovie(gif)
gif.start()
layout.addWidget(loading)
widget = QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
app = QApplication([])
window = MainWindow()
window.show()
app.exec()
My gif is from here:
https://icons8.com/preloaders/en/circular
and it's called Position.gif
That's what it looks like in my app.
Any ideas on how to improve it would be great!
I am using Qt Designer to create a main window and I have the following result:
The above opened with PyQt6 using the following code:
from PyQt6.QtWidgets import QApplication, QMainWindow
from PyQt6 import uic
import sys
class UI(QMainWindow):
def __init__(self):
super().__init__()
uic.loadUi("form.ui", self)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = UI()
window.show()
sys.exit(app.exec())
However, in the Qt designer the actual form looks sth like this:
As you can notice the x, y and z text and line edits look weird and dimensionally different from the Qt Designer.
There I have a layout in layout and for some reason the the inner layout shrinks. Is it actually possible to fix the error in Qt Designer without modifying the code?
Thank you for your attention!
Edit 1:
Outer layout Property - Value pairs:
Inner layout Property - Value pairs:
How do you make a QGraphicsScene with a specified size and a QGraphicsView to monitor that scene with the same size?
This sounds like a stupid question but consider the following test code [1]
import sys
from PyQt4 import QtGui, QtCore
class MainWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.scene = QtGui.QGraphicsScene(0, 0, 200, 200, self)
self.view = QtGui.QGraphicsView(self.scene, self)
#self.view.setMaximumSize(200, 200)
self.setCentralWidget(self.view)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())
When I run this I get a little window with the QGraphicsView and no scroll bars. If I shrink the window scroll bars appear because I've made the view smaller than the specified size of the scene. If I enlarge the window the bars go away and the view resizes with the window. All of this makes sense.
Now I run the same code again but with the commented line (preceded by #) un-commented. The Window appears with the view inside, but the view has scroll bars. When I shrink the window the view also shrinks, but when I enlarge the window the view only enlarges to a certain size. This is not surprising. What is surprising is that with the view at it's maximum size, the scroll bars are still there. I don't understand this because the maximum size of the view is explicitly matched to the size of the scene in the code.
Why does this happen?
I am aware that other questions have explained how to force the scene and view to fit together but I want to understand what size view and scene I have actually made, hence my attempt to use explicitly specified sizes.
[1] I'm using PyQt, C++ users just read "self" as "this" and "import" as "#include"
EDIT: The accepted answer below is absolutely correct. I would just like to add for others who read this that if your view is in a layout you have to account for the layout margins as well. These can be explicitly set in the QtDesigner etc.
Ok, I worked it out for you!
The QGraphicsView (which subclasses QFrame) has a border. If you add the below line to your init method:
self.view.setFrameShape(QtGui.QFrame.NoFrame)
then you remove the 1px frame and it works as you expect!
I have a QMainWindow that is a child to another window. When the user clicks anywhere in the parent window, I do not want the child window to be minimized. The child window should lose the focus and user should be able to continue working on the parent window.
This functionality is similar to the find/replace dialogs found in libreoffice/excel/openoffice etc as shown below. We can see that the task-bar shows only the parent application window and the child window is not visible in task-bar.
Are there any signals on QMainWindow that could help me achieve this? Or what would be the best way to do this?
If you open the new window as Dialog and give it a parent, it should stay on top of the parent. Since you're using QMainWindow, you can pass this with the constructor. If you decide to use QDialog, make sure you make it modeless with setModal(False). Otherwise it will block the parent.
A small example:
import sys
from PyQt4 import QtGui, QtCore
class Window(QtGui.QMainWindow):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
w = QtGui.QWidget()
layout = QtGui.QVBoxLayout(w)
self.button = QtGui.QPushButton('Open Dialog')
self.text = QtGui.QTextEdit()
layout.addWidget(self.button)
layout.addWidget(self.text)
self.setCentralWidget(w)
self.button.clicked.connect(self.openDialog)
def openDialog(self):
self.dialog = QtGui.QMainWindow(self, QtCore.Qt.Dialog)
self.dialog.show()
app = QtGui.QApplication(sys.argv)
w = Window()
w.show()
sys.exit(app.exec_())
I didn't find this on the web...
What does this opaqueResize property on QSplitter (see doc) stand for?
Thanks.
I am not really sure what you are asking here. It's all in the docs.
QSplitter resizes its children
dynamically by default. If you would
rather have QSplitter resize the
children only at the end of a resize
operation, call setOpaqueResize(false)
Meaning if you set setOpaqueResize(false) on your splitter, start your application and try to pull the splitter to resize the widgets it holds it will not actually resize widgets until you release the splitter. On the other hand if it is set to true it will try to resize the widgets while you are dragging the splitter handle.
It can be useful to turn this feature off if your custom widgets take long time to draw for example since it would make resizing quite slow.
But to answer your question, property opaqueResize holds whether resizing is opaque or not, i.e. will it resize the widgets while dragging the splitter or not.
Example:
Here is a PyQt example you can try (I had example laying around in Python, but it should work the same in C++):
from PyQt4 import QtGui, QtCore
class Example(QtGui.QWidget):
def __init__(self, *args, **kwargs):
super(Example, self).__init__(*args, **kwargs)
top = QtGui.QLabel('test', self)
bottom = QtGui.QPushButton('test', self)
splitter = QtGui.QSplitter(QtCore.Qt.Vertical)
# Try changing from False to True
splitter.setOpaqueResize(False)
splitter.addWidget(top)
splitter.addWidget(bottom)
hbox = QtGui.QHBoxLayout(self)
hbox.addWidget(splitter)
self.setLayout(hbox)
self.setGeometry(250, 200, 350, 250)
def main():
app = QtGui.QApplication([])
ex = Example()
ex.show()
app.exec_()
if __name__ == '__main__':
main()
Hope this makes things a bit clearer.