Найти - Пользователи
Полная версия: Рисование Qt
Начало » GUI » Рисование Qt
1 2
hellslade
Добрый день, всем.
Появилась мысль научиться рисовать на рабочем столе. К примеру, линию под курсором мыши или прямоугольную область (подобно выделению). Вот только незнаю с чего начать. Пробовал гуглить – находил обрывки кода на Delphi. На Python ничего..

Как я понимаю, нужно получить объект desktop'a и с помощью QPainter'a рисовать на нем?
QtGui.QApplication.desktop() это и есть то, что мне нужно? Или всетаки нет?

Написал вот такое (точнее собрал из нескольких найденных скриптов). Пока рисование на виджете
# -*- coding: cp1251 -*-

from PyQt4 import QtCore, QtGui
import sys
import os

class MainForm(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)

self.scribbling = False
self.myPenWidth = 1
self.myPenColor = QtCore.Qt.blue
self.lastPoint = QtCore.QPoint()

def mousePressEvent(self, event):
if event.button() == QtCore.Qt.LeftButton:
self.lastPoint = event.pos()
self.scribbling = True

def mouseMoveEvent(self, event):
if (event.buttons() & QtCore.Qt.LeftButton) and self.scribbling:
self.drawLineTo(event.pos())

def mouseReleaseEvent(self, event):
if event.button() == QtCore.Qt.LeftButton and self.scribbling:
self.drawLineTo(event.pos())
self.scribbling = False

def drawLineTo(self, endPoint):
painter = QtGui.QPainter()
painter.begin(self)
painter.setPen(QtGui.QPen(self.myPenColor, self.myPenWidth, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin))
painter.drawLine(self.lastPoint, endPoint)
painter.end()

rad = self.myPenWidth / 2 + 2
self.update(QtCore.QRect(self.lastPoint, endPoint).normalized().adjusted(-rad, -rad, +rad, +rad))
self.lastPoint = QtCore.QPoint(endPoint)

class App(QtGui.QApplication):
def __init__(self, *args):
QtGui.QApplication.__init__(self, *args)
self.ui = MainForm(None)
self.ui.show()

if __name__ == "__main__":
app = App(sys.argv)
app.exec_()
Ругается на меня матом
QPainter::begin: Paint device returned engine == 0, type: 1
QPainter::setPen: Painter not active
QPainter::end: Painter not active, aborted
Ну не вижу просто в чем косяк, опыта маловато. Ткните, плиз, носом :)
Вроде все правильно написано. Если drawLineTo обозвать paintEvent (и соответственно определить endPoint), то линия рисуется.

Наставьте на путь истинный (применение розг не возбраняется) :)
pasaranax
Я правда никогда не рисовал на рабочем столе, но попробуй посмотреть в сторону QDesktopWidget.
hellslade
pasaranax, QDesktopWidget может и то, что нужно
QWidget * QDesktopWidget::screen ( int screen = -1 )
Returns a widget that represents the screen with index screen. This widget can be used to draw directly on the desktop, using an unclipped painter like this:
QPainter paint( QApplication::desktop()->screen( 0 ), TRUE );
paint.draw…

paint.end();
Но я всеравно не могу догнать, как правильно написать. Пишу так
    def drawLineTo(self, endPoint):
painter = QtGui.QPainter()
painter.begin(QtGui.QApplication.desktop().screen())
painter.setPen(QtGui.QPen(self.myPenColor, self.myPenWidth, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin))
painter.drawLine(self.lastPoint, endPoint)
painter.end()
Ругается также как и в первом моем посте.
Пишу так
    def drawLineTo(self, endPoint):
painter = QtGui.QPainter()
painter.begin(QtGui.QApplication.desktop().screen(), True)
painter.setPen(QtGui.QPen(self.myPenColor, self.myPenWidth, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin))
painter.drawLine(self.lastPoint, endPoint)
painter.end()
Говорит, что слишком много аргументов. Т.е. через QtGui.QApplication.desktop().screen() я могу получить количество экранов, размеры экрана и все…Кто может помочь? Очень бы хотелось порисовать.
pasaranax
Максимум, чего получилось достичь, это создание прозначного виджета, на котором можно рисовать. Вот простейший пример:
#!/usr/bin/env python2.6
# coding: utf-8
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

class Widget(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint)
self.setAttribute(Qt.WA_TranslucentBackground)

def paintEvent(self, event):
painter = QPainter(self)
painter.setBrush(Qt.blue)
painter.drawEllipse(0, 0, 100, 100)

if __name__ == '__main__':
app = QApplication(sys.argv)
w = Widget()
w.resize(105, 105)
w.show()
sys.exit(app.exec_())

Также, можно делать полупрозрачность с использованием png. Вот тут нашел. Направление для копания есть :D очень интересная тема!

аддед: вот еще по той же теме: http://vingrad.ru/blogs/sabrog/2009/01/10/qt-440-kak-prevratit-kartinku-v-okno-legko/
hellslade
pasaranax
Тема, конечно, интересная. Ссылки посмотрел – интересно, спасибо.
Вообще я об этом задумался, когда в очередной раз увидел программу для снятия скриншотов, в которой можно выделять произвольную область.
Как это сделать, кроме как рисованием на экране? Нарисовать прозрачный виджет, перед тем как рисовать выделение?
Займусь этим как проект закончится…
pasaranax
А можно ссылку на эту программу?
hellslade
pasaranax, даже незнаю как она называется :) не пользуюсь я такими, потому как скриншоты делаю ооочень редко. А вот шеф мой скриншоты очень любит, у него ее и увидел. Узнаю как называется и вечером выложу
Zubchick
http://habrahabr.ru/blogs/habraware/57587

у самого давно тайная мечта сделать что-то аналогичное с заливкой на имейджзхак или что-то подобное.
hellslade
Да, програмулька наподобие: включил, выделил область, сохранил на диск.
+ Такое встречается в разных приложениях. Недавно пришлось написать небольшой хепл с помощью Help&Manual5, там есть такая же возможность делать скрины: при включении этой возможности, около курсора появляется маленькое окошко с координатами. при этом можно делать все что угодно (двигать окна, менять размеры, печатать)…Зажал Ctrl и кликнул – делается снимок. Вот как они такое реализуют? Что за технология такая? :)
hellslade
Всем снова здрасте.
Вот чего удалось добиться по теме “Рисование на рабочем столе”. К Qt это отношение уже в принципе не имеет, но раз началали здесь, то тут и продолжу. Да и гуй ко всему этому напишу всеравно на Qt
# -*- coding: cp1251 -*-
from pythoncom import PumpMessages
from pyHook import HookManager
import win32gui
from win32con import PS_SOLID
import win32con
import win32api

global scribbling, lastPoint, controlDown

def OnKeyboardEvent(event):
global scribbling, lastPoint, controlDown
if event.GetMessageName() == 'key down' and event.Key in ['Lcontrol', 'Rcontrol']:
controlDown = True
elif event.GetMessageName() == 'key up' and event.Key in ['Lcontrol', 'Rcontrol']:
controlDown = False
return True # False делать опасно! Скрипт НЕ передаст сигнал системе

def OnMouseDown(event):
global scribbling, lastPoint
if event.GetMessageName() == 'mouse left down' and controlDown:
lastPoint = event.Position
scribbling = True
return False
return True
def OnMouseUp(event):
global scribbling
if event.GetMessageName() == 'mouse left up' and scribbling:
drawLineTo(event.Position)
scribbling = False
return True
def OnMouseMove(event):
global scribbling
if scribbling:
drawLineTo(event.Position)
# return False
return True
def drawLineTo(endPoint):
global lastPoint
x1,y1 = lastPoint
x2,y2 = endPoint
lastPoint = endPoint
clRed = 0x0000ED # Цвет для рисования
# Получаем контекст экрана рабочего стола
screenDC = win32gui.GetDC(None)
# Создаем новые карандаш и кисть
penHandle = win32gui.CreatePen(PS_SOLID, 1, clRed)
oldPenHandle = win32gui.SelectObject(screenDC, penHandle)

brushHandle = win32gui.CreateSolidBrush(clRed)
oldBrushHandle = win32gui.SelectObject(screenDC, brushHandle)
# Рисуем на рабочем столе
""" Рисование прямоугольника
left = 100
top = 100
width = 200
height = 300
win32gui.Rectangle(screenDC, left, top, left+width, top + height)
# """
win32gui.MoveToEx(screenDC,x1, y1)
win32gui.LineTo(screenDC,x2,y2)
# Освобождаем память от карандаша, кисти и указателя на рабочий стол
win32gui.SelectObject(screenDC, oldBrushHandle)
win32gui.DeleteObject(brushHandle)

win32gui.SelectObject(screenDC, oldPenHandle)
win32gui.DeleteObject(penHandle)

win32gui.ReleaseDC(0, screenDC)

scribbling = False
lastPoint = None
controlDown = False

hookm = HookManager()
# Определям функцию на перехват
hookm.MouseLeftDown = OnMouseDown
hookm.MouseLeftUp = OnMouseUp
hookm.MouseMove = OnMouseMove
# Определям функцию на перехват клавиши
hookm.KeyDown = OnKeyboardEvent
hookm.KeyUp = OnKeyboardEvent
# Указываем перехватывать события
hookm.HookMouse()
hookm.HookKeyboard()
# Запускаем все действо
PumpMessages()
Запускаем скрипт, зажимаем Ctrl, левую клавишу мыши и рисуем.

По сути работает, но не совсем так, как хотелось бы
Еще не решенные проблемы:
1. При рисовании, хотелось бы менять курсор в системе на крест. Так было б виднее откуда линия начнет рисоваться.
Пробовал так:
hCurs1 = win32api.LoadCursor(0, win32con.IDC_CROSS)
win32api.SetCursor(hCurs1)
И ничего не происходит.
2. Надо как-то отключить(?) обновление окон. Ибо при обновлении нарисованные линии стираются. Заметил это когда рисовал в месте мигания курсора. По решению этого мыслей пока никаких.

3. После того, как отпустили мышу(прикратили рисовать) нужно стереть все нарисованное.
Вроде пока все. У кого какие мысли по этим вопросам? Может кто-нить поможет код допилить? Или пните в нужном направлении
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB