WM_SETICON的一点注意

本文探讨了Windows应用程序中图标设置的方法及细节。通过使用 SendMessage 函数,可以分别设置应用程序的大图标(ICON_BIG)和小图标(ICON_SMALL)。文章指出,ICON_BIG 影响 Alt+Tab 切换时显示的图标,而 ICON_SMALL 则用于标题栏和任务栏图标。如果设置了小图标,则后续更改图标时必须使用 ICON_SMALL,否则变化仅体现在 Alt+Tab 显示上。

今天用SendMessage(hwnd, WM_SETICON, ICON_BIG, hIcon );改图标的时候,看到点问题,记录下

ICON_BIG大图标所说的是Alt+Tab后的显示图标

ICON_SMALL小图标是标题栏的图标和任务栏里显示的图标

如果没有设置小图标,那么以后只设大图标,Alt+Tab、标题栏、任务栏都会变,但是,一旦设置过了小图标,不管是初始化

还是后来再设置的,只要设置过一次,要改变标题栏和任务栏的图标就得用ICON_SMALL小图标了,再用ICON_BIG的效果就只能Alt+Tab才能看到了

/////////////////////////////////////////////////////////////

MSDN中也提到一句,也应该是这意思,以上是学习的时候试的...


你修改一下,现在只能是二维,如果多维的也要处理,import sys import win32api import win32gui import win32clipboard import win32con import time import threading import keyboard # 需要安装:pip install keyboard from datetime import datetime, date from PyQt5.QtWidgets import (QApplication, QMainWindow, QMessageBox, QVBoxLayout, QLabel, QPushButton, QLineEdit, QWidget, QTableWidget, QTableWidgetItem, QHBoxLayout, QGroupBox, QDialog, QFormLayout, QDialogButtonBox) from PyQt5.QtCore import Qt, QThread, pyqtSignal, QTimer # 检查日期限制 EXPIRY_DATE = datetime(2026, 6, 1) if datetime.now() > EXPIRY_DATE: QMessageBox.critical(None, "过期提示", "此软件已过期,无法使用。") sys.exit(1) def show_error_message(message): """显示错误信息对话框。""" msg = QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setText(message) msg.setWindowTitle("错误") msg.setStandardButtons(QMessageBox.Ok) msg.exec_() def show_success_message(message): """显示成功信息对话框。""" msg = QMessageBox() msg.setIcon(QMessageBox.Information) msg.setText(message) msg.setWindowTitle("成功") msg.setStandardButtons(QMessageBox.Ok) msg.exec_() def get_window_handle_at_mouse_cursor(): """获取当前鼠标光标位置下的窗口句柄。""" cursor_pos = win32api.GetCursorPos() hwnd = win32gui.WindowFromPoint(cursor_pos) return hwnd def clear_window_content(hwnd): """清空窗口内容""" # 检查窗口是否有效 if not win32gui.IsWindow(hwnd): return False # 尝试获取窗口类名 try: class_name = win32gui.GetClassName(hwnd) # 对于编辑框控件 if class_name in ["Edit", "RichEdit", "RichEdit20W"]: win32gui.SendMessage(hwnd, win32con.EM_SETSEL, 0, -1) # 全选 win32gui.SendMessage(hwnd, win32con.WM_CLEAR, 0, 0) # 清除 return True except: pass # 通用方法 try: win32gui.SendMessage(hwnd, win32con.WM_SETTEXT, 0, "") return True except: return False def send_text_directly(hwnd, text): """直接向窗口发送文本""" # 检查窗口是否有效 if not win32gui.IsWindow(hwnd): return False # 尝试获取窗口类名 try: class_name = win32gui.GetClassName(hwnd) # 对于编辑框控件 if class_name in ["Edit", "RichEdit", "RichEdit20W"]: win32gui.SendMessage(hwnd, win32con.WM_SETTEXT, 0, text) # 发送回车 win32gui.PostMessage(hwnd, win32con.WM_KEYDOWN, win32con.VK_RETURN, 0) win32gui.PostMessage(hwnd, win32con.WM_KEYUP, win32con.VK_RETURN, 0) return True except: pass # 通用方法 try: # 先清空内容 win32gui.SendMessage(hwnd, win32con.WM_SETTEXT, 0, "") # 发送文本 win32gui.SendMessage(hwnd, win32con.WM_SETTEXT, 0, text) # 发送回车 win32gui.PostMessage(hwnd, win32con.WM_KEYDOWN, win32con.VK_RETURN, 0) win32gui.PostMessage(hwnd, win32con.WM_KEYUP, win32con.VK_RETURN, 0) return True except: return False def get_clipboard_data_as_list(): """获取剪贴板内容并返回一维或二维列表。""" for _ in range(3): # 重试3次 try: win32clipboard.OpenClipboard(None) clipboard_data = win32clipboard.GetClipboardData(win32con.CF_UNICODETEXT) win32clipboard.CloseClipboard() lines = [line.strip() for line in clipboard_data.split('\n') if line.strip()] if any('\t' in line for line in lines): return [line.split('\t') for line in lines] else: return lines except Exception: try: win32clipboard.CloseClipboard() except: pass time.sleep(0.1) return [] class SenderThread(QThread): """发送线程,支持停止功能""" progress = pyqtSignal(int, int) # 当前进度,总数量 finished = pyqtSignal(bool, str) # 是否成功,消息 error = pyqtSignal(str) # 错误消息 def __init__(self, parent, hwnds, data, delay): super().__init__(parent) self.hwnds = hwnds # 窗口句柄列表 self.data = data # 要发送的数据 self.delay = delay # 延时 self._stop_flag = False # 停止标志 def stop(self): """停止发送""" self._stop_flag = True def run(self): """执行发送操作""" try: total = len(self.data) for i, item in enumerate(self.data): # 检查停止标志 if self._stop_flag: self.finished.emit(False, "用户停止发送") return # 检查窗口句柄是否有效 for hwnd in self.hwnds: if not win32gui.IsWindow(hwnd): self.error.emit(f"目标窗口已关闭或句柄无效: {hwnd}") self.finished.emit(False, "窗口已关闭") return # 发送数据 if isinstance(item, list): # 二维数据 if len(item) != len(self.hwnds): self.error.emit(f"数据维度与窗口数量不匹配: {len(item)} != {len(self.hwnds)}") continue for j, text in enumerate(item): if not send_text_directly(self.hwnds[j], text): self.error.emit(f"向窗口 {self.hwnds[j]} 发送数据失败") else: # 一维数据 if not send_text_directly(self.hwnds[0], item): self.error.emit(f"向窗口 {self.hwnds[0]} 发送数据失败") # 更新进度 self.progress.emit(i + 1, total) # 延时 time.sleep(self.delay) self.finished.emit(True, "发送完成") except Exception as e: self.finished.emit(False, f"发送过程中发生错误: {str(e)}") class ClipboardApp(QMainWindow): def __init__(self): super().__init__() self.sender_thread = None self.stop_requested = False self.initUI() self.setWindowTitle(f"剪贴板自动发送工具 (按F8停止)") # 设置热键处理 self.hotkey_timer = QTimer(self) self.hotkey_timer.timeout.connect(self.check_hotkey) self.hotkey_timer.start(100) # 每100毫秒检查一次热键 def initUI(self): self.setGeometry(300, 300, 800, 600) central_widget = QWidget() self.setCentralWidget(central_widget) layout = QVBoxLayout() # 添加预览区域 preview_layout = QHBoxLayout() preview_btn = QPushButton("预览剪贴板", self) preview_btn.clicked.connect(self.preview_clipboard) preview_layout.addWidget(preview_btn) layout.addLayout(preview_layout) # 添加表格预览 self.table = QTableWidget(self) self.table.setMinimumHeight(300) layout.addWidget(self.table) # 进度标签 self.progress_label = QLabel("准备就绪", self) layout.addWidget(self.progress_label) # 延时设置 delay_layout = QHBoxLayout() delay_label = QLabel("发送延时(秒):", self) self.delay_input = QLineEdit(self) self.delay_input.setPlaceholderText("输入延时") self.delay_input.setText("1.0") # 默认值 delay_layout.addWidget(delay_label) delay_layout.addWidget(self.delay_input) layout.addLayout(delay_layout) # 说明标签 self.label = QLabel( "使用说明:\n" "1. 复制要发送的内容\n" "2. 点击预览按钮查看内容\n" "3. 设置发送延时\n" "4. 点击开始后将鼠标移动到目标窗口\n" "5. 按F8键可随时停止发送" ) layout.addWidget(self.label) # 按钮布局 button_layout = QHBoxLayout() # 开始按钮 self.start_button = QPushButton('开始发送', self) self.start_button.clicked.connect(self.start) button_layout.addWidget(self.start_button) # 停止按钮 self.stop_button = QPushButton('停止发送', self) self.stop_button.clicked.connect(self.stop_sending) self.stop_button.setEnabled(False) button_layout.addWidget(self.stop_button) layout.addLayout(button_layout) # 添加有效期提示 expiry_label = QLabel(f"如有问题请联系我", self) expiry_label.setStyleSheet("color: red; font-weight: bold;") layout.addWidget(expiry_label) central_widget.setLayout(layout) def check_hotkey(self): """检查热键是否被按下""" if keyboard.is_pressed('f8'): self.stop_sending() # 等待按键释放,避免连续触发 while keyboard.is_pressed('f8'): time.sleep(0.1) def preview_clipboard(self): """预览剪贴板内容""" try: data = get_clipboard_data_as_list() if not data: show_error_message("剪贴板为空") return # 判断是一维还是二维数据 if isinstance(data[0], list): # 二维数据 rows = len(data) cols = max(len(row) for row in data) self.table.setRowCount(rows) self.table.setColumnCount(cols) # 填充数据 for i, row in enumerate(data): for j, value in enumerate(row): item = QTableWidgetItem(str(value)) self.table.setItem(i, j, item) else: # 一维数据 self.table.setRowCount(len(data)) self.table.setColumnCount(1) # 填充数据 for i, value in enumerate(data): item = QTableWidgetItem(str(value)) self.table.setItem(i, 0, item) # 自动调整列宽 self.table.resizeColumnsToContents() self.progress_label.setText(f"已加载 {len(data)} 行数据") show_success_message("预览已更新") except Exception as e: show_error_message(f"预览失败: {str(e)}") def start(self): """开始处理剪贴板内容""" try: self.delay = float(self.delay_input.text()) except ValueError: show_error_message("请输入有效的延时!") return # 获取当前表格中的数据 rows = self.table.rowCount() cols = self.table.columnCount() if rows == 0: show_error_message("没有数据可发送!") return self.progress_label.setText("请在5秒内移动鼠标到目标窗口...") QApplication.processEvents() # 更新UI time.sleep(5) hwnd = get_window_handle_at_mouse_cursor() # 检查窗口是否有效 if not win32gui.IsWindow(hwnd): show_error_message("目标窗口无效或已关闭!") return if cols == 1: # 一维数据 data = [ self.table.item(row, 0).text() for row in range(rows) if self.table.item(row, 0) ] hwnds = [hwnd] else: # 二维数据 self.progress_label.setText("请在5秒内移动鼠标到第二个目标窗口...") QApplication.processEvents() # 更新UI time.sleep(5) hwnd1 = get_window_handle_at_mouse_cursor() # 检查窗口是否有效 if not win32gui.IsWindow(hwnd1): show_error_message("第二个目标窗口无效或已关闭!") return # 构建二维数据 data = [] for row in range(rows): row_data = [] for col in range(cols): item = self.table.item(row, col) row_data.append(item.text() if item else "") data.append(row_data) hwnds = [hwnd, hwnd1] # 创建并启动发送线程 self.sender_thread = SenderThread(self, hwnds, data, self.delay) self.sender_thread.progress.connect(self.update_progress) self.sender_thread.finished.connect(self.sending_finished) self.sender_thread.error.connect(self.show_error) # 更新UI状态 self.start_button.setEnabled(False) self.stop_button.setEnabled(True) self.progress_label.setText("开始发送...按F8键停止") self.sender_thread.start() def stop_sending(self): """停止发送操作""" if self.sender_thread and self.sender_thread.isRunning(): self.sender_thread.stop() self.stop_button.setEnabled(False) self.progress_label.setText("正在停止...") def update_progress(self, current, total): """更新进度显示""" self.progress_label.setText(f"发送进度: {current}/{total} ({current / total * 100:.1f}%)") def sending_finished(self, success, message): """发送完成处理""" self.start_button.setEnabled(True) self.stop_button.setEnabled(False) if success: self.progress_label.setText(message) show_success_message(message) else: self.progress_label.setText(f"发送失败: {message}") show_error_message(message) def show_error(self, message): """显示错误消息""" self.progress_label.setText(f"错误: {message}") show_error_message(message) def closeEvent(self, event): """窗口关闭事件处理""" if self.sender_thread and self.sender_thread.isRunning(): self.sender_thread.stop() self.sender_thread.wait(2000) # 等待2秒 # 停止热键检查计时器 self.hotkey_timer.stop() event.accept() if __name__ == '__main__': app = QApplication(sys.argv) # 再次检查日期限制(双保险) if datetime.now() > EXPIRY_DATE: QMessageBox.critical(None, "过期提示", "此软件已过期,无法使用。") sys.exit(1) main_window = ClipboardApp() main_window.show() sys.exit(app.exec_())
08-23
// ImageSystemDlg.cpp: 实现文件 // #include "pch.h" #include "framework.h" #include "ImageSystem.h" #include "ImageSystemDlg.h" #include "afxdialogex.h" #ifdef _DEBUG #define new DEBUG_NEW #endif // CImageSystemDlg 对话框 CImageSystemDlg::CImageSystemDlg(CWnd* pParent /*=nullptr*/) : CDialogEx(IDD_IMAGESYSTEM_DIALOG, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CImageSystemDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); DDX_Control(pDX, IDC_PICTURE1, m_p1); DDX_Control(pDX, IDC_PICTURE2, m_p2); } BEGIN_MESSAGE_MAP(CImageSystemDlg, CDialogEx) ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_STN_CLICKED(IDC_PICTURE2, &CImageSystemDlg::OnStnClickedPicture2) ON_BN_CLICKED(IDC_BUTTON1, &CImageSystemDlg::OnBnClickedButton1) ON_BN_CLICKED(IDC_BUTTON3, &CImageSystemDlg::OnBnClickedButton3) ON_STN_CLICKED(IDC_PICTURE1, &CImageSystemDlg::OnStnClickedPicture1) END_MESSAGE_MAP() // CImageSystemDlg 消息处理程序 BOOL CImageSystemDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } // 如果向对话框添加最小化按钮,则需要下面的代码 // 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序, // 这将由框架自动完成。 void CImageSystemDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // 使图标在工作区矩形中居中 int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // 绘制图标 dc.DrawIcon(x, y, m_hIcon); } else { CDialogEx::OnPaint(); } } //当用户拖动最小化窗口时系统调用此函数取得光标 //显示。 HCURSOR CImageSystemDlg::OnQueryDragIcon() { return static_cast<HCURSOR>(m_hIcon); } void CImageSystemDlg::OnStnClickedPicture2() { // TODO: 在此添加控件通知处理程序代码 } // stdafx.h 添加 void CImageSystemDlg::OnBnClickedButton1() { // TODO: 在此添加控件通知处理程序代码 CString fileName; TCHAR szFilter[] = _T("JPEG文件(*.jpg)|*.jpg|GIF文件(*.gif)|*.gif|bmp文件(*.bmp)|*.bmp||"); CFileDialog fileDlg(TRUE, _T("jpg"), NULL, 0, szFilter, this); if (fileDlg.DoModal() != IDOK) //没有点确定按钮,返回 return; fileName = fileDlg.GetPathName(); CImage image; //创建图片对象,保存图片信息 image.Load(fileName); CRect rectControl; m_p1.GetClientRect(rectControl); CDC* pDc = m_p1.GetDC(); image.Draw(pDc->m_hDC, rectControl); image.Destroy(); m_p1.ReleaseDC(pDc); } // 对话框按钮事件 void CImageSystemDlg::OnBnClickedButton3() { // TODO: 在此添加控件通知处理程序代码 UINT i; i = MessageBox(_T("确定退出?"), _T("提示"), MB_YESNO | MB_ICONQUESTION); if (i == IDYES) { exit(0); } } void CImageSystemDlg::OnStnClickedPicture1() { // TODO: 在此添加控件通知处理程序代码 } 为什么我用·按键1打开图片时遇到bmp文件就不显示,遇到jpg文件就变畸形
最新发布
09-04
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值