如何使用Python在Windows上直接在屏幕上绘制?

3

我希望在用户屏幕上创建视觉提示,但是我发现找不到一个简单的解决方案,如何在屏幕上直接进行基本绘图而不限制用户操作(使用Python 3.x在Windows下)。

经过搜索,我唯一找到的 - 不完全有效的 - 解决方案是使用wxPython。以下是代码:

import wx

# init
app=wx.App()
dc=wx.ScreenDC()

# set line and fill style
dc.SetBrush(wx.TRANSPARENT_BRUSH) 
dc.SetPen(wx.Pen((255, 0, 0), width=3, style=wx.PENSTYLE_SOLID))

# draw (x, y, width, height)
dc.DrawRectangle(100, 100, 200, 100)

代码在屏幕上绘制,但由于Windows快速重新绘制屏幕,结果几乎不可见。我尝试了一个解决方法,使用for循环重复绘图命令,但是闪烁的矩形几乎不可见(这不是我想向客户展示的内容)。
更好一点(接近足够)的方法是使用一个透明的TKinter窗口(没有标题栏),并将其显示一段较短的时间。以下是该方法的工作代码(有一个缺点,在代码下面进行了解释):
from tkinter import *

def HighlightSection(Rect=(100,100,300,200), Color = 'red', Duration = 3):
    win= Tk()
    GeometryString = str(Rect[0])+'x'+str(Rect[1])+'+' \
                     +str(Rect[2])+'+'+str(Rect[3])
    win.geometry(GeometryString) # "200x100+300+250" # breite, höhe, x, y # 
    win.configure(background=Color)
    win.overrideredirect(1)
    win.attributes('-alpha', 0.3)
    win.wm_attributes('-topmost', 1)
    win.after(Duration * 1000, lambda: win.destroy())
    win.mainloop()

这里有一件事情我无法解决:有没有办法使得TKinter“窗口”可以被点击穿过?如果能够实现这一点,那么这就足够好了。只要不是点击穿透,用户就无法在/在高亮区域下进行操作!

有没有简单而稳定的解决方案,可以在屏幕上绘制(线条、矩形、文本)并在定义的时间后将其清除?任何帮助都将不胜感激!提前感谢您,Ulrich!


为什么不使用Pygame库? - Rishabh Semwal
将您的代码放在while循环内部。它将继续显示对象。 - Rishabh Semwal
循环结果时会出现奇怪的闪烁,与Windows屏幕重绘冲突。 - Ulrich
3个回答

0

我相信将任何东西绘制到屏幕上都需要一个窗口。这个窗口可以是部分透明的,但它必须存在。

使用PyQt5可能会对您有所帮助。这将为您提供一个透明的主窗口并绘制几条线:

import sys
from PyQt5.QtGui import QPainter, QPen
from PyQt5.QtWidgets import QMainWindow, QApplication
from PyQt5.QtCore import Qt


class Clear(QMainWindow):

    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        self.setGeometry(300, 300, 280, 270)
        self.setStyleSheet("background:transparent")
        self.setAttribute(Qt.WA_TranslucentBackground)
        self.show()

    def paintEvent(self, e):
        qp = QPainter()
        qp.begin(self)
        self.drawLines(qp)
        qp.end()

    def drawLines(self, qp):
        pen = QPen(Qt.blue, 2, Qt.SolidLine)

        qp.setPen(pen)
        qp.drawLine(20, 40, 250, 40)

        pen.setStyle(Qt.DashLine)
        qp.setPen(pen)
        qp.drawLine(20, 80, 250, 80)

        pen.setStyle(Qt.DashDotLine)
        qp.setPen(pen)
        qp.drawLine(20, 120, 250, 120)

        pen.setStyle(Qt.DotLine)
        qp.setPen(pen)
        qp.drawLine(20, 160, 250, 160)

        pen.setStyle(Qt.DashDotDotLine)
        qp.setPen(pen)
        qp.drawLine(20, 200, 250, 200)

        pen.setStyle(Qt.CustomDashLine)
        pen.setDashPattern([1, 4, 5, 4])
        qp.setPen(pen)
        qp.drawLine(20, 240, 250, 240)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = Clear()
    sys.exit(app.exec_())

参考来源:http://zetcode.com/gui/pyqt5/painting/ - 我稍微修改了一下以调整透明度。


好的,我刚刚尝试了一下,结果只是一个窗口显示在屏幕上。这和其他几十个库所能做的没什么区别...抱歉... - Ulrich

0

这个可行,已在带有Python 3.x的macOS上进行了测试。

from PyQt5.QtGui import (QPainter,
                         QPen,
                         QColor)
from PyQt5.QtWidgets import (QMainWindow,
                             QApplication)
from PyQt5.QtCore import (Qt,
                          QCoreApplication,
                          QTimer)


class TransparentWindow(QMainWindow):

    def __init__(
            self,
            x: int,
            y: int,
            width: int,
            height: int,
            pen_color: str,
            pen_size: int):
        super().__init__()
        self.highlight_x = x
        self.highlight_y = y
        self.highlight_width = width
        self.highlight_height = height
        self.pen_color = pen_color
        self.pen_size = pen_size
        self.initUI()

    def initUI(self):
        """Initialize the user interface of the window."""
        self.setGeometry(
            self.highlight_x,
            self.highlight_y,
            self.highlight_width + self.pen_size,
            self.highlight_height + self.pen_size)
        self.setStyleSheet('background: transparent')
        self.setWindowFlag(Qt.FramelessWindowHint)

    def paintEvent(self, event):
        """Paint the user interface."""
        painter = QPainter()
        painter.begin(self)
        painter.setPen(QPen(QColor(self.pen_color), self.pen_size))
        painter.drawRect(
            self.pen_size - 1,
            self.pen_size - 1,
            self.width() - 2 * self.pen_size,
            self. height() - 2 * self.pen_size)
        painter.end()


def highlight_on_screen(
        x: int,
        y: int,
        width: int,
        height: int,
        pen_color: str = '#aaaa00',
        pen_size: int = 2,
        timeout: int = 2):
    """Highlights an area as a rectangle on the main screen.

        `x` x position of the rectangle

        `y` y position of the rectangle

        `width` width of the rectangle

        `height` height of the rectangle

        `pen_color` Optional: color of the rectangle as a hex value;
                              defaults to `#aaaa00`

        `pen_size` Optional: border size of the rectangle; defaults to 2

        `timeout` Optional: time in seconds the rectangle
                            disappears; defaults to 2 seconds
        """
    app = QApplication([])
    window = TransparentWindow(x, y, width, height, pen_color, pen_size)
    window.show()
    QTimer.singleShot(timeout * 1000, QCoreApplication.quit)
    app.exec_()


highlight_on_screen(0, 0, 100, 100)

屏幕上的矩形结果

enter image description here

然而,在macOS上,无法在应用栏上方绘制窗口。在Windows上不应该出现这个问题。


0
这个很好用,它使用透明窗口和PyQt在屏幕中间直接绘制一个白色的圆圈。圆圈后面的所有内容都是可交互的。
import sys
from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtGui import QPainter, QBrush, QColor
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget

# Global variables for circle parameters
circle_radius = 50
outline_width = 2
outline_color = Qt.white

class GameOverlay(QWidget):
    def __init__(self):
        super().__init__()

        self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
        self.setAttribute(Qt.WA_TranslucentBackground)

        screen = QApplication.primaryScreen()
        screen_geometry = screen.geometry()

        screen_width = screen_geometry.width()
        screen_height = screen_geometry.height()

        self.setGeometry(0, 0, screen_width, screen_height)  # Set the overlay size to match the screen
        self.show()

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)

        # Draw a transparent background
        painter.setBrush(QBrush(QColor(0, 0, 0, 0)))
        painter.drawRect(self.rect())

        # Calculate the circle's center position
        circle_center_x = self.width() // 2
        circle_center_y = self.height() // 2

        # Draw the circle outline
        painter.setPen(QColor(outline_color))
        painter.setBrush(QBrush(QColor(0, 0, 0, 0)))
        painter.drawEllipse(circle_center_x - circle_radius, circle_center_y - circle_radius,
                            circle_radius * 2, circle_radius * 2)

def main():
    app = QApplication(sys.argv)
    overlay = GameOverlay()

    timer = QTimer()
    timer.timeout.connect(overlay.update)
    timer.start(16)  # Update the overlay approximately every 16 milliseconds (about 60 FPS)

    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接