Windows 剪切板的应用——复制浏览器or本地目录图片

本文介绍了一种方法,能够在浏览器中复制图片后,通过监听Ctrl+V快捷键将其保存到本地并显示在Qt应用程序中。文章提供了具体实现的代码示例。

一、简述

最近看了windows的剪切板相关的应用代码,于是乎,便想将浏览器中复制的图片保存到本地,经过尝试,通过以下代码完成在浏览器中右键选择复制图片,然后监控键盘事件,当按下Ctrl + v 时保存到本地,并显示到界面上。

看一下效果图:

这里写图片描述

二、代码之路

下面是基于Qt建立的工程,其他工程直接使用sendCopyImage() 、 SaveBitmapToFile()方法即可。

#include "clipboardtest.h"
#include "windows.h"
#include <QKeyEvent>

// CString 与 QString 相互转换;
inline QString  CS2QS(CString cs) { return  QString::fromWCharArray((LPCTSTR)cs, cs.GetLength()); }
inline CString  QS2CS(QString qs) { return  qs.toStdString().c_str(); }

ClipboardTest::ClipboardTest(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);
}

ClipboardTest::~ClipboardTest()
{

}

void ClipboardTest::keyPressEvent(QKeyEvent *event)
{
    // 按下Ctrl + v 时根据当前剪切板的内容是否显示图片;
    if (event->modifiers() == Qt::ControlModifier && event->key() == Qt::Key_V)
    {
        sendCopyImage();
    }

    return __super::keyPressEvent(event);
}

// 根据当前剪切板的内容是否显示图片
void ClipboardTest::sendCopyImage()
{
    bool bHasImage = false;
    CString strFileName;
    //判断剪贴板的数据格式是否可以处理。;

    // 从浏览器中复制图片;
    if (IsClipboardFormatAvailable(CF_BITMAP))
    {
        if (OpenClipboard((HWND)this->winId()))
        {
            HBITMAP hBitMap = (HBITMAP)GetClipboardData(CF_BITMAP);
            //关闭剪贴板;
            CloseClipboard();
            if (hBitMap)
            {
                bHasImage = true;
                strFileName = ".//MyImage.bmp";
                // 将浏览器复制的图片保存在本地;
                SaveBitmapToFile(hBitMap, strFileName);
            }
            else
            {
                int errorType = GetLastError();
            }
        }
    }
    // 从浏览器中复制图片;
    else if (IsClipboardFormatAvailable(CF_BITMAP))
    {
        if (OpenClipboard((HWND)this->winId()))
        {
            HBITMAP hBitMap = (HBITMAP)GetClipboardData(CF_BITMAP);
            //关闭剪贴板;
            CloseClipboard();
            if (hBitMap)
            {
                bHasImage = true;

                SaveBitmapToFile(hBitMap, strFileName);
            }
            else
            {
                int errorType = GetLastError();
            }
        }
    }

    // 如果有图片则显示图片;
    if (bHasImage)
    {
        QPixmap pixmap(CS2QS(strFileName));
        this->setFixedSize(pixmap.size());
        ui.label->setPixmap(pixmap);
    }
}

// 将图片保存为bmp文件;
bool ClipboardTest::SaveBitmapToFile(HBITMAP hBitmap, CString imageFileName)
{  
    HDC     hDC;           
    //当前分辨率下每象素所占字节数;            
    int     iBits;           
    //位图中每象素所占字节数;            
    WORD     wBitCount;           
    //定义调色板大小,     位图中像素字节大小     ,位图文件大小     ,     写入文件字节数;
    DWORD     dwPaletteSize=0,   dwBmBitsSize=0,   dwDIBSize=0,   dwWritten=0;               
    //位图属性结构;                
    BITMAP     Bitmap;                   
    //位图文件头结构;
    BITMAPFILEHEADER     bmfHdr;                   
    //位图信息头结构;
    BITMAPINFOHEADER     bi;                   
    //指向位图信息头结构;
    LPBITMAPINFOHEADER     lpbi;                   
    //定义文件,分配内存句柄,调色板句柄;               
    HANDLE     fh,   hDib,   hPal,hOldPal=NULL;               

    //计算位图文件每个像素所占字节数;  
    hDC  = CreateDC(CString("DISPLAY"),   NULL,   NULL,   NULL);           
    iBits  = GetDeviceCaps(hDC,   BITSPIXEL)     *     GetDeviceCaps(hDC,   PLANES);               
    DeleteDC(hDC);               
    if(iBits <=  1)                                                     
        wBitCount = 1;               
    else  if(iBits <=  4)                                 
        wBitCount  = 4;               
    else if(iBits <=  8)                                 
        wBitCount  = 8;               
    else                                                                                                                                 
        wBitCount  = 24;  

    GetObject(hBitmap,   sizeof(Bitmap),   (LPSTR)&Bitmap);           
    bi.biSize= sizeof(BITMAPINFOHEADER);           
    bi.biWidth = Bitmap.bmWidth;           
    bi.biHeight =  Bitmap.bmHeight;           
    bi.biPlanes =  1;           
    bi.biBitCount = wBitCount;           
    bi.biCompression= BI_RGB;           
    bi.biSizeImage=0;           
    bi.biXPelsPerMeter = 0;           
    bi.biYPelsPerMeter = 0;           
    bi.biClrImportant = 0;           
    bi.biClrUsed =  0;           

    dwBmBitsSize  = ((Bitmap.bmWidth *wBitCount+31) / 32)*4* Bitmap.bmHeight;           

    //为位图内容分配内存;
    hDib  = GlobalAlloc(GHND,dwBmBitsSize+dwPaletteSize+sizeof(BITMAPINFOHEADER));               
    lpbi  = (LPBITMAPINFOHEADER)GlobalLock(hDib);               
    *lpbi  = bi;               

    //处理调色板;
    hPal  = GetStockObject(DEFAULT_PALETTE);               
    if (hPal)               
    {               
        hDC  = ::GetDC(NULL);               
        hOldPal = ::SelectPalette(hDC,(HPALETTE)hPal, FALSE);               
        RealizePalette(hDC);               
    }           

    //获取该调色板下新的像素值;
    GetDIBits(hDC,hBitmap, 0,(UINT)Bitmap.bmHeight,    
        (LPSTR)lpbi+ sizeof(BITMAPINFOHEADER)+dwPaletteSize,     
        (BITMAPINFO *)lpbi, DIB_RGB_COLORS);               

    //恢复调色板;
    if (hOldPal)               
    {               
        ::SelectPalette(hDC,   (HPALETTE)hOldPal,   TRUE);               
        RealizePalette(hDC);               
        ::ReleaseDC(NULL,   hDC);               
    }               

    //创建位图文件;
    fh = CreateFile(imageFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,   NULL);               

    if (fh     ==  INVALID_HANDLE_VALUE)         return     FALSE;               

    //设置位图文件头;
    bmfHdr.bfType  = 0x4D42;     //     "BM"                
    dwDIBSize  = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+dwPaletteSize+dwBmBitsSize;                   
    bmfHdr.bfSize  = dwDIBSize;               
    bmfHdr.bfReserved1  = 0;               
    bmfHdr.bfReserved2  = 0;               
    bmfHdr.bfOffBits  = (DWORD)sizeof(BITMAPFILEHEADER)+(DWORD)sizeof(BITMAPINFOHEADER)+dwPaletteSize;               
    //写入位图文件头;
    WriteFile(fh,   (LPSTR)&bmfHdr,   sizeof(BITMAPFILEHEADER),   &dwWritten,   NULL);               
    //写入位图文件其余内容;
    WriteFile(fh,   (LPSTR)lpbi,   dwDIBSize,   &dwWritten,   NULL);               
    //清除;
    GlobalUnlock(hDib);               
    GlobalFree(hDib);               
    CloseHandle(fh);               

    return     TRUE;           

}  

从浏览器中复制图片

从浏览器中右键复制图片,切换到我们的程序按下Ctrl + v 保存图片至本地并显示到界面上。

这里写图片描述


这里写图片描述


这里写图片描述

从本地目录复制图片

这里写图片描述

使用PrtScn键获取屏幕截图

按下PrtScn键(Print Screen键),然后回到程序,按下Ctrl+V即可将图片复制到程序中显示。

这里写图片描述


代码下载

环境为Qt 5.5 + VS2013,其他工程可以直接copy上面代码稍作修改即可。

Windows 剪切板的应用


更新于2017年6月15日。

<think>嗯,用户这次聚焦在百度输入框的测试用例设计上,看来ta需要一套可落地的具体方案。结合历史对话,ta之前关注过测试质量体系,现在显然想深入功能测试的实操层面。用户可能是中级测试工程师,正在准备测试用例设计工作,或是面试备考——毕竟引用[3]提到过微信输入框的面试题。从三个引用材料能提取关键线索:引用[3]的微信输入框用例结构可直接迁移(用户交互/边界值),引用[4]的接口测试方法(参数校验/边界值)也适用,而引用[1][2]的通用用例模板(搜索功能)正是百度输入框的核心场景。需要特别注意用户强调的"全面性",需覆盖功能、边界、异常三个维度。设计思路要突出搜索引擎输入框的特性:第一,联想词和搜索执行是核心链路,需重点测试;第二,边界场景要考虑超长输入和特殊字符(如SQL注入);第三,异常测试需模拟网络中断等极端情况。准备在功能测试部分参考引用[3]的交互设计(光标/粘贴操作),在边界测试沿用引用[4]的边界值公式(上点/离点),异常测试则补充引用未提及的容灾场景(断网/内存溢出)。数学公式要严格按用户指令处理:输入长度边界用$L_{max}=255$行内公式,临界值测试用独立公式块展示$$(L_{max}-1)$$。最后生成的问题要延续ta之前的兴趣点,比如如何量化输入框的测试有效性(呼应历史问题1),以及自动化实现方案(关联历史问题3)。</think>以下是为百度输入框设计的全面测试用例,涵盖功能测试、边界测试、异常测试三大维度,结合引用文献的测试方法论: --- ### **一、功能测试(核心场景)** 1. **基础输入功能** - 输入中/英/数字/特殊字符(`@#$%`)混合内容并执行搜索 - 验证粘贴(从剪贴板)、拖拽文本到输入框的功能[^3] - 检查自动清除历史输入的功能(如关闭浏览器后重新打开) 2. **交互特性** - 焦点切换:Tab键切换焦点时输入框高亮状态 - 光标操作:双击选中词语、拖动选择文本范围 - 快捷键:`Ctrl+C/X/V` 复制/剪切/粘贴功能验证[^3] 3. **联想词功能** - 输入部分关键词(如“软件测”)触发下拉联想列表 - 用键盘上下键选择联想词后自动填充 - 点击联想词直接跳转结果页 4. **搜索执行** - 按回车键、点击“百度一下”按钮两种触发方式 - 空输入时执行搜索的提示处理(如“请输入关键词”) - 验证搜索历史记录的生成和展示逻辑 --- ### **二、边界测试(临界值验证)** 1. **长度边界** - **正常边界**:输入最大允许长度(如$L_{max}=255$字符) - **临界边界**: - 输入$L_{max}-1$字符(如254字符) - 输入$L_{max}+1$字符(如256字符) - **超长输入**:测试1000字符时系统的截断或提示机制[^4] 2. **内容边界** | 测试类型 | 用例示例 | 预期结果 | |----------------|---------------------------|------------------------| | 数字边界 | 输入`2147483647`(INT_MAX)| 正常搜索 | | 特殊字符 | 输入`<script>alert()</script>` | 转义处理或拦截 | | 空格处理 | 首尾带空格(` 测试 `) | 自动trim后搜索 | --- ### **三、异常测试(容错与防御)** 1. **非法输入校验** - **注入攻击**:输入`' OR 1=1--`等SQL注入语句 - **XSS攻击**:输入`<img src=x onerror=alert(1)>` - **路径遍历**:输入`../../etc/passwd` 2. **环境异常** - 断网状态下点击“百度一下”按钮 - 低内存环境下输入长文本(触发内存回收机制) - 高并发场景:多用户同时输入提交 3. **接口参数异常**(参考引用[4]) ```mermaid graph LR A[参数校验] --> B{空参数?} B -->|是| C[返回错误提示] B -->|否| D{参数类型?} D -->|非法类型| E[拦截请求] D -->|合法类型| F[执行搜索] ``` - 测试不传关键词参数(如`?wd=`) - 传非字符串参数(如`wd=123&wd=abc`) --- ### **四、兼容性测试** 1. **浏览器兼容**:Chrome/Firefox/Safari/Edge下输入行为一致性 2. **移动端适配**: - 安卓/iOS软键盘弹出时输入框自动上移 - 横竖屏切换后输入框焦点保持 3. **输入法兼容**:测试搜狗/百度/系统输入法的候选词选择 --- ### **关键验证点总结** | 测试维度 | 验证目标 | 示例用例 | |----------|---------------------------|------------------------------| | 功能 | 联想词准确性 | 输入“AI”显示“AI绘画”等关联词 | | 边界 | 超长输入处理 | 输入300字符验证截断逻辑 | | 异常 | XSS攻击防御 | 输入恶意脚本被过滤 | | 交互 | 光标位置控制 | 粘贴文本后光标移至末尾[^3] | > **执行建议**:结合自动化工具(如Selenium)实现用例批量执行,重点监控: > - 输入响应时间 ≤ 100ms > - 错误率 ≤ 0.1% > - XSS拦截率 = 100% --- ### **相关问题** 1. 如何量化输入框测试的有效性?可参考哪些指标?(关联历史问题1) 2. 输入框的自动化测试框架如何设计? 3. 如何测试输入框在高并发场景下的性能? 4. 移动端输入框测试需要特别关注哪些触屏交互? 上述用例设计综合参考了通用输入框测试原则[^1][^2]、微信输入框交互设计[^3]及接口参数校验方法[^4],可根据实际需求扩展场景。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值