Este artigo pressupõe que você já estudou o artigo anterior.Se você ainda não estudou, vá aprender rapidamente. Siga os blogueiros para saber mais.
Diretório de artigos
prefácio
Após o último estudo, instalamos o mecanismo de reconhecimento do tesseract e reconhecemos rapidamente o conteúdo da imagem por meio do pytesseract. Em seguida, PyQt5DesignMode
criamos nosso projeto por meio do modelo de projeto, e a interface do software foi desenhada e um evento de clique simples foi adicionado para o botão de captura de tela.
Neste artigo, continuaremos a melhorar este projeto e realizar a função de captura de tela do QQ.
1. Finalidade da tarefa
Com base na seção anterior, realize a função de captura de tela do QQ, salve a imagem e exiba-a na interface do software.
Exigir
- Você pode usar as teclas de atalho para tirar screenshots
- Você pode clicar no botão de captura de tela para tirar uma captura de tela
- Capturas de tela são exibidas no software
2. Implemente a função de captura de tela
1. Análise da função de captura de tela
Base teórica
1. Função de captura de tela
O Qt fornece uma maneira de tirar screenshots - grabWindow
, o protótipo da função
def grabWindow(WID window, x=0, y=0, width=-1, height=-1)
Os argumentos são 窗口ID
e 要截取的区域
(uma área retangular de x, y, largura e altura).
窗口ID
Pode ser obtido através do winId() do QWidget. Se o ID da janela da tela inteira for interceptado, passe 0.
2. Suporta evento de movimento do mouse
Os QWidgets do Qt fornecem um método que permite que a janela suporte eventos de movimento do mouse - mouseTracking
, indicando se a propriedade de rastreamento do mouse da janela está em vigor. protótipo de função
def setMouseTracking(self, bool)
O parâmetro possui apenas um bool
tipo de parâmetro, indicando se deseja habilitar eventos de rastreamento do mouse.
3. Janela sem bordas
Os QWidgets do Qt fornecem um método que pode tornar a janela sem bordas - setWindowFlag
o sinalizador da janela precisa ser passado, ou seja, Qt_WindowType
para habilitar janelas de estilos diferentes. protótipo de função
def setWindowFlag(self, Qt_WindowType, on=True)
O principal parâmetro que usamos aqui é Qt_WindowType
para indicar o estilo da janela, e suas opções são as seguintes
Qt::Widget
: O valor padrão do construtor QWidget. Se o novo widget não tiver um widget pai, é uma janela independente, caso contrário, é um widget filho.Qt::Window
: Quer haja ou não um widget pai, o novo widget é uma janela, geralmente com uma borda de janela e uma barra de título.Qt::Dialog
: O novo widget é uma caixa de diálogoQt::Sheet
: O novo widget é um formulário do Macintosh.Qt::Drawer
: O novo widget é uma gaveta do Macintosh.Qt::Popup
: o novo widget é uma janela pop-up de nível superior.Qt::Tool
: O novo widget é uma janela de ferramentas, que geralmente é uma pequena janela usada para exibir botões de ferramentas.
Se uma janela de ferramentas tiver um widget pai, ele será exibido no topo do widget pai, caso contrário, será equivalente a usarQt::WindowStaysOnTopHint
Exibir.Qt::Tooltip
: O novo widget é uma janela de prompt sem barra de título e borda da janela.Qt::SplashScreen
: O novo widget é uma janela de boas-vindas, que é o valor padrão do construtor QSplashScreen.Qt::Desktop
: O novo widget é a área de trabalho, que é o padrão para o construtor QDesktopWidget.Qt::SubWindow
: o novo widget é uma janela filho, independentemente de o widget ter ou não um widget pai.Qt::X11BypassWindowManagerHint
: Ignora completamente o gerenciador de janelas. Sua função é gerar uma janela sem moldura de janela que não é gerenciada. Neste momento, o usuário não pode usar o teclado para inserir a menos que a função QWidget::ActivateWindow() seja chamada manualmente.Qt::FramelessWindowHint
: Produz uma janela sem bordas de janela, neste momento o usuário não pode mover a janela e alterar seu tamanho.Qt::CustomizeWindowHint
: desative a dica de título da janela padrão.
4. Tela cheia da janela
Os QWidgets do Qt fornecem um método que pode tornar a exibição da janela em tela cheia - setWindowState
, o que significa definir o estado da janela. protótipo de função
def setWindowState(self, Union, Qt_WindowStates=None, Qt_WindowState=None):
Quando o usamos, usamos principalmente Qt_WindowState
, e suas opções são as seguintes
Qt: :WindowNoState
estado normalQt: :WindowMinimized
janela minimizadaQt:: WindowMaximized
maximizar janelaQt::WindowFullScreen
A janela preenche toda a tela e não tem bordasQt:: Window Active
Uma janela que se torna ativa, por exemplo, pode receber entrada do teclado
Ideias de implementação
Herde a classe QWidgets para implementar uma janela de tela inteira sem bordas, cobrindo a tela inteira e fornecendo um plano de fundo preto transparente.
Manipule os seguintes eventos conforme mostrado na figura abaixo
- Pressione o botão esquerdo do mouse para gravar as coordenadas iniciais
- Pressione o botão direito do mouse para cancelar a operação
- Movimento do mouse, gravar coordenadas do mouse
- Solte o botão esquerdo do mouse e registre as coordenadas finais do movimento do mouse
- Clique duas vezes com o mouse para salvar o conteúdo da captura de tela
- Evento de desenho, desenha a caixa arrastada pelo mouse em tempo real
A lógica aqui deve ser algo assim. Quando o botão esquerdo do mouse é pressionado, as coordenadas da posição clicada do mouse começam a ser registradas. Quando o mouse se move, uma nova coordenada é atualizada. A nova coordenada e a coordenada anterior podem calcular x, y, largura e altura da área retangular em tempo real. Quando o botão esquerdo do mouse for liberado, as coordenadas deste ponto serão gravadas e calculadas com as primeiras coordenadas iniciais para obter as coordenadas da área da captura de tela.
O evento de movimento do mouse está sempre em execução, porque queremos visualizar o efeito de nossas capturas de tela em tempo real, portanto, precisamos sempre obter a posição do mouse. Ao mesmo tempo, o evento de desenho também precisa rodar o tempo todo, precisa calcular a área retangular que visualizamos em tempo real e desenhá-la na interface.
O evento do botão direito do mouse é muito simples, que é cancelar a operação atual, sua lógica é que se uma área estiver selecionada no momento, cancele essa área, e se nenhuma área estiver selecionada, feche a janela. O efeito final é o seguinte.
2. Realização da função de captura de tela
As ideias de código a seguir vêm de usuários do CSDN
@Karbob
, obrigado por suas ideias.
1. Crie uma janela
Crie uma janela que herde o QWidget, e definimos a janela basicamente. init_window
O método é o que usamos para inicializar a janela, habilitamos a função de rastreamento do mouse, configuramos o cursor do mouse, configuramos a janela sem bordas e a janela em tela cheia.
class CaptureScreen(QWidget):
def __init__(self):
super(QWidget, self).__init__()
self.init_window() # 初始化窗口
self.capture_full_screen() # 获取全屏
def init_window(self):
self.setMouseTracking(True) # 鼠标追踪
self.setCursor(Qt.CrossCursor) # 设置光标
self.setWindowFlag(Qt.FramelessWindowHint) # 窗口无边框
self.setWindowState(Qt.WindowFullScreen) # 窗口全屏
Vale ressaltar que tiramos uma captura de tela da tela inteira da área de trabalho quando a janela foi inicializada e salvamos no campo da janela, que será usado quando fizermos a captura de tela posteriormente.
self.capture_full_screen() # 获取全屏
Sua implementação é chamar grabWindow
o método para tirar uma captura de tela da área de trabalho. O código de implementação é o seguinte,
def capture_full_screen(self):
self.full_screen_image = QGuiApplication.primaryScreen().grabWindow(QApplication.desktop().winId())
Existem também algumas variáveis que precisam ser inicializadas
begin_position = None
end_position = None
full_screen_image = None
capture_image = None
is_mouse_pressLeft = None
painter = QPainter()
begin_position
Representa as coordenadas iniciais do mouseend_position
Representa as coordenadas finais do mousefull_screen_image
Imagem para armazenar capturas de tela em tela cheiacapture_image
imagem capturadais_mouse_pressLeft
Se o botão esquerdo do mouse é pressionadopainter
o objeto para desenhar
2. Implemente o evento de pressionamento do mouse
O evento mouse down faz principalmente duas coisas,
- Determinar se o botão esquerdo do mouse ou o botão direito do mouse é pressionado
- Se for o botão esquerdo do mouse, registre a posição inicial do mouse, caso contrário, cancele a operação atual
O fluxograma do manipulador de eventos é mostrado abaixo,
O código de implementação é o seguinte,
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.begin_position = event.pos()
self.is_mouse_pressLeft = True
if event.button() == Qt.RightButton:
# 如果选取了图片,则按一次右键开始重新截图
if self.capture_image is not None:
self.capture_image = None
self.paint_background_image()
self.update()
else:
self.close()
3. Implemente o evento de movimento do mouse
O principal trabalho do evento de movimento do mouse é obter as coordenadas do mouse em tempo real e, em seguida, chamar o método de atualização dos widgets para atualizar a interface. O código aqui é o seguinte
def mouseMoveEvent(self, event):
if self.is_mouse_pressLeft is True:
self.end_position = event.pos()
self.update()
4. Implemente o evento de liberação do mouse
A principal tarefa do evento de liberação do mouse é registrar as coordenadas quando o mouse é liberado e, em seguida, is_mouse_pressLeft
defini-lo como falso para indicar que o mouse não está mais pressionado. O código é o seguinte
def mouseReleaseEvent(self, event):
self.end_position = event.pos()
self.is_mouse_pressLeft = False
5. Implemente o evento de desenho
Na verdade, o evento de desenho executa duas coisas: uma é definir a imagem de fundo como uma captura de tela da área de trabalho e escurecer a cor; a outra é colocar a imagem retangular sem escurecer a cor na área selecionada pelo mouse.
def paintEvent(self, event):
self.painter.begin(self) # 开始重绘
self.paint_background_image()
pen_color = QColor(30, 144, 245) # 画笔颜色
self.painter.setPen(QPen(pen_color, 1, Qt.SolidLine, Qt.RoundCap)) # 设置画笔,蓝色,1px大小,实线,圆形笔帽
if self.is_mouse_pressLeft is True:
pick_rect = self.get_rectangle(self.begin_position, self.end_position) # 获得要截图的矩形框
self.capture_image = self.full_screen_image.copy(pick_rect) # 捕获截图矩形框内的图片
self.painter.drawPixmap(pick_rect.topLeft(), self.capture_image) # 填充截图的图片
self.painter.drawRect(pick_rect) # 画矩形边框
self.painter.end() # 结束重绘
No código, self.paint_background_image()
é o método de desenhar um fundo cinza-preto. Seu código de implementação é o seguinte
def paint_background_image(self):
shadow_color = QColor(0, 0, 0, 100) # 黑色半透明
self.painter.drawPixmap(0, 0, self.full_screen_image)
self.painter.fillRect(self.full_screen_image.rect(), shadow_color) # 填充矩形阴影
self.get_rectangle(self.begin_position, self.end_position)
Calcule o retângulo da área de seleção do quadro do mouse, o código de implementação é o seguinte,
def get_rectangle(self, begin_point, end_point):
pick_rect_width = int(qAbs(begin_point.x() - end_point.x()))
pick_rect_height = int(qAbs(begin_point.y() - end_point.y()))
pick_rect_top = begin_point.x() if begin_point.x() < end_point.x() else end_point.x()
pick_rect_left = begin_point.y() if begin_point.y() < end_point.y() else end_point.y()
pick_rect = QRect(pick_rect_top, pick_rect_left, pick_rect_width, pick_rect_height)
# 避免高度宽度为0时候报错
if pick_rect_width == 0:
pick_rect.setWidth(2)
if pick_rect_height == 0:
pick_rect.setHeight(2)
return pick_rect
Calcular o retângulo é realmente muito simples, sua ideia é registrar as coordenadas inicial e final, para que a largura e a altura do retângulo possam ser calculadas através das coordenadas finais, então as duas fórmulas a seguir são obtidas
H ( z ) = y 1 − y , W ( z ) = x 1 − x H(z) = y1-y, W(z) = x1-xH ( z )=a 1−y ,W ( z )=x 1−x
Existem mais dois pontos importantes aqui, que são interceptar os gráficos da área do retângulo do mouse, calcular a área de seleção do quadro do mouse através do método acima e, em seguida, copiar a imagem original da área de seleção do quadro do mouse, que usamos para full_screen_image.copy
obter
pick_rect = self.get_rectangle(self.begin_position, self.end_position) # 获得要截图的矩形框
self.capture_image = self.full_screen_image.copy(pick_rect) # 捕获截图矩形框内的图片
O processo de implementação real aqui é o seguinte Através
das coordenadas iniciais e w e h do retângulo, podemos determinar qual área queremos e passá-la full_screen_image.copy
para obter uma captura de tela da área correspondente. QRect é um tipo de dados, então só precisamos passar dados do tipo QRect.
6. Evento de clique duplo do mouse
No evento de clique duplo do mouse, chamamos a função de salvar a imagem e, em seguida, fechamos a janela.
Isso está relacionado à ligação entre os seguintes programas de janela, portanto, deve ser lido em conjunto com o conteúdo de acompanhamento
Seu código de implementação é o seguinte
def mouseDoubleClickEvent(self, event):
if self.capture_image is not None:
self.save_image()
self.close()
3. Passe a captura de tela para a interface principal
Crie um arquivo no pacote do controlador CaptureScreen.py
e herde-o UI_CaptureScreen.py
. Vamos escrever a lógica entre as janelas.
Chamamos save_image() no evento de clique duplo do mouse. Aqui a implementamos
def save_image(self):
self._signal[QPixmap].emit(self.capture_image)
Um sinal é acionado aqui, o seguinte é a definição do sinal
_signal = pyqtSignal(QPixmap)
O sinal de disparo pode transferir dados entre janelas, aqui definimos um sinal do tipo QPixmap, e então usamos um slot na MainWindow para receber esses dados
self.screenWindow._signal[QPixmap].connect(self.handle_capture_picture)
Depois existe o método de tratamento desses dados, ou seja, após receber os dados, exibi-los na Etiqueta
@pyqtSlot(QPixmap)
def handle_capture_picture(self, img):
print("获取到图片", img)
self.img_raw = img
local_img = QPixmap(img).scaled(self.picture_label.width(), self.picture_label.height())
# self.picture_label.setScaledContents(True)
self.picture_label.setPixmap(local_img)
A lógica acima é que, quando o save_image acionar o sinal, o handle_capture_picture de MainWIndow processará o sinal e, em seguida, colocará a imagem na interface.
4. Realize a captura de tela da tecla de atalho
Observe a captura de tela da tecla de atalho A biblioteca system_hotkey é usada aqui, que também é a tecla de atalho global implementada pelo slot de sinal usado. Primeiro, defina um sinal
sig_keyhot = pyqtSignal(str)
e, em seguida, conecte-se à função do manipulador
self.sig_keyhot[str].connect(self.MKey_pressEvent)
Inicializar duas teclas de atalho e registrar teclas de atalho
self.hk_start, self.hk_stop = SystemHotkey(), SystemHotkey()
self.hk_start.register(('control', '1'), callback=lambda x: self.send_key_event("capture_start"))
self.hk_stop.register(('control', '2'), callback=lambda x: self.send_key_event("None"))
Depois, há a função de manipulador
@pyqtSlot(str)
def MKey_pressEvent(self, i_str):
if i_str == 'capture_start':
self.screenWindow.show()
elif i_str == 'None':
QMessageBox.information(self, '温馨提示', '其他功能请等待后续添加哦')
Resumir
O acima é todo o conteúdo deste artigo. Este artigo completa a função de captura de tela deste projeto, usa o método nativo do pyqt para realizar a captura de tela e responde à interface principal, que também é uma das funções poderosas do PyQt5DesignMode , que melhora a eficiência de desenvolvimento do programa.
Esta pequena ferramenta é apenas uma parte deste projeto. Na verdade, adicionaremos ferramentas como conversão de formato pdf posteriormente até que este projeto possa ser publicado. Aguarde os próximos artigos.
PyQt5DesignMode é um modelo de projeto implementado por mim combinando ideias MVC com pyqt5. Destina-se a realizar aplicativos multi-janela com pyqt5. Se você estiver interessado, por favor me dê um star
.
Bem-vindo ao se inscrever nesta coluna para aprender mais sobre python.