python 调用Windows函数编写Windows程序,这一次在第一次基础上增加滚动条,绘图函数,以及输出文件内容 同时演示C语言数组结构如何在python中使用

 这次主要演示C语言结构类型在python中如何使用 因为涉及知识点多 所以可以选择性查看部分代码  部分用到的外部文件,都在第一版中,这里不再重复,同时演示最终效果图  供初学者参考

import datetime
import sys
import structure1
from winsound import PlaySound
import winsound
import win32gui
import win32con
import ctypes
import cv2
import win32api
import ctypes.wintypes
import paintProc
import math
#引入systemMetrics函数数据
import systemMetricsDic1
import time
user32 = ctypes.windll.user32
gdi32=ctypes.windll.gdi32
import Globalvariable1
winmm=ctypes.windll.LoadLibrary(r"./winmm.dll")
debug=True
SND_FILENAME=0x20000
SND_ASYNC=0x01
#--------因为python是解释型语言 所以回调函数最先创建----------------------------------------
# cv2.namedWindow("img",cv2.WINDOW_NORMAL)  #cv2.WINDOW_NORMAL窗口大小可变
# cvHwnd= win32gui.FindWindow(None, "img")
#
# print(cvHwnd)
keyDisplay=True
closeDisplay=False
crColor=0
pStringBuffer= ctypes.create_string_buffer(b"Hello",Globalvariable1.stringBufferSize)
def LOWORD(x):
    return x & 0xffff
def HOWORD(x):
    return (x>>16) & 0xffff
def MAX(a,b):
    if a>b:
        return a
    else:
        return b
def MIN(a,b):
    if a<b:
        return a
    else:
        return b
def windowProc(hwnd, msg, wParam, lParam):
    si=structure1.SCROLLINFO()
    ps=structure1.PAINTSTRUCT()
    iPaintBeg=0
    iPaintEnd=0


    match msg:
        case win32con.WM_CREATE:
            # region Description  初始化事件
            if debug:
                print("窗口第一次创建\n")
                PlaySound("./hello.wav",winsound.SND_ASYNC)

            hdc = user32.GetDC(hwnd)
            crColor=gdi32.GetPixel(hdc,15,15)
            print("位置(15,15)处的颜色值为:",crColor)
            r,g,b=Globalvariable1.getRGB(crColor)
            print("位置(15,15)处的颜色值为:", r,g,b)
            #------------自定义的结构类型--------------------
            tm = structure1.TEXTMETRIC()
            #采用引用类型 以便能修改传入的参数
            gdi32.GetTextMetricsA(hdc, ctypes.byref(tm))

            Globalvariable1.global_cxChar = tm.tmAveCharWidth
            Globalvariable1.global_cyChar = tm.tmHeight + tm.tmExternalLeading
            #tmPitchAndFamily低位为1 变宽字体 否则为等宽字体
            if tm.tmPitchAndFamily & 0x1:
                Globalvariable1.global_cxCaps = 1.5*Globalvariable1.global_cxChar
            else:
                Globalvariable1.global_cxCaps = 1 * Globalvariable1.global_cxChar

            user32.ReleaseDC(hwnd, hdc)
            cWidth=Globalvariable1.global_cxChar
            Globalvariable1.global_int_VerticalScrollMaxPosition=40*cWidth + 44*Globalvariable1.global_cxCaps
            # endregion
            return 0

        case win32con.WM_SIZE:
            # region Description  处理窗口改变尺寸事件
            Globalvariable1.global_cyClient = HOWORD(lParam)
            Globalvariable1.global_cxClient = LOWORD(lParam)
            # lParam 低位字为客户区宽度  高位字为客户区高度   通常行数就为lines=cyClient/cyChar   colomuns=cxClient/cxChar
            #为滚动条结构信息赋初值  设置垂直滚动条
            si.cbSize=ctypes.sizeof(si)
            si.fMask=win32con.SIF_RANGE | win32con.SIF_PAGE
            si.nMin=0
            si.nMax=Globalvariable1.global_int_displayHaveMaxLinesInClient
            if Globalvariable1.global_cyChar!=0:
               si.nPage=Globalvariable1.global_cyClient//Globalvariable1.global_cyChar
            user32.SetScrollInfo(hwnd,win32con.SB_VERT,ctypes.byref(si),True)

            #设置水平滚动条
            si.cbSize = ctypes.sizeof(si)
            si.fMask = win32con.SIF_RANGE | win32con.SIF_PAGE
            si.nMin = 0
            if Globalvariable1.global_cxChar!=0:
                si.nMax = 2+(Globalvariable1.global_int_HorizontalScrollMaxPosition//Globalvariable1.global_cxChar)
            if Globalvariable1.global_cxChar != 0:
                si.nPage = Globalvariable1.global_cxClient // Globalvariable1.global_cxChar
            user32.SetScrollInfo(hwnd, win32con.SB_HORZ, ctypes.byref(si), True)

            if debug:
                print("如果是第一个WM_SIZE消息,通常由调用ShowWindow函数产生")
                print("你改变了窗口尺寸,消息编号是:", msg, " ", hex(msg), "wParam的值是:", wParam, "  lParam的值是:", lParam)
                print("wParam的值是窗口状态")
                if wParam == win32con.SIZE_RESTORED:
                    print("  窗口为创建时的尺寸:SIZE_RESTORED:", win32con.SIZE_RESTORED)
                if wParam == win32con.SIZE_MINIMIZED:
                    print("  窗口最小化:SIZE_MINIMIZED:", win32con.SIZE_MINIMIZED)
                if wParam == win32con.SIZE_MAXIMIZED:
                    print("  窗口最大化:SIZE_MAXIMIZED:", win32con.SIZE_MAXIMIZED)
                if wParam == win32con.SIZE_MAXSHOW:
                    print("  当其他某个窗口还原到原来的大小时,消息将发送到所有弹出窗口:SIZE_MAXSHOW:", win32con.SIZE_MAXSHOW)
                if wParam == win32con.SIZE_MAXHIDE:
                    print("  当其他某个窗口最大化时,消息将发送到所有弹出窗口:SIZE_MAXHIDE:", win32con.SIZE_MAXHIDE)
                print("lParam的值是窗口尺寸数值:")
                print("  lParam低位窗口客户区新宽度:", LOWORD(lParam))
                print("  lParam高位窗口客户区新宽度:", HOWORD(lParam))
            # endregion
            return 0


        case win32con.WM_PAINT:
            #产生WN_PAINT消息的的情况  客户区被隐藏又重现 用户改变窗口大小 调用ScrollWindow或者ScrollDC函数 调用InvalidateRect或InvalidateRgn函数
            #擦除覆盖的消息框或者对话框 下拉菜单出现与消失 显示工具提示

            #收到该消息 必须使无效区域变为有效区域才返回 不然Windows会一直发生WM_PAINT消息 直到区域有效
            # print("接收到绘制消息",msg)
            hdc=user32.BeginPaint(hwnd,ctypes.byref(ps))
            #hdc只是客户区无效区域
            # print(ps)
            # hdc=win32gui.GetDC(hwnd)
            si.cbSize=ctypes.sizeof(si)
            si.fMask=win32con.SIF_POS
            #------------01 start --获取客户区画图------------------------
            rect=structure1.RECT()
            user32.GetClientRect(hwnd,ctypes.byref(rect))
            print("客户区矩形:",rect.left,rect.top,rect.right,rect.bottom)
            # region Description  绘制表格
            # x=0
            # for i in range(rect.right):
            #     x=x+100
            #     gdi32.MoveToEx(hdc,x,0,None)
            #     gdi32.LineTo(hdc,x,rect.bottom)
            #     if x>rect.right:
            #        break
            # y=0
            # for i in range(rect.bottom):
            #     y=y+100
            #     gdi32.MoveToEx(hdc,0,y,None)
            #     gdi32.LineTo(hdc,rect.right,y)
            #     if y>rect.bottom:
            #        break
            # endregion

            # region Description  任务02 绘制一个矩形-
            #------------------任务02 绘制一个矩形----------------------------------------
            ptArray=structure1.POINT *5
            aarray= ptArray()
            i=1
            for ii in aarray:
                ii.x=i+1
                ii.y=i+2
                i=i*2
            for bb in aarray:
                print("这是测试:",bb.x)

            pt=[100,100,200,100,200,200,100,200,100,100]
            gdi32.MoveToEx(hdc, pt[0], pt[1], None)
            for i in range(len(pt)):
                if i %2==0:
                    gdi32.LineTo(hdc,pt[i],pt[i+1])
            #-------------------任务02结束 -------------------------------------
            # endregion

            # region Description  输出文字
            #-------------01  end---------------
            #获取垂直滚动框的位置
            user32.GetScrollInfo(hwnd,win32con.SB_VERT,ctypes.byref(si))
            Globalvariable1.global_int_VerticalScrollCurrentPosition=si.nPos

            #获取水平滚动框的位置
            user32.GetScrollInfo(hwnd,win32con.SB_HORZ,ctypes.byref(si))
            Globalvariable1.global_int_HorizontalScrollCurrentPosition=si.nPos

            iVertPos=Globalvariable1.global_int_VerticalScrollCurrentPosition
            if Globalvariable1.global_cyChar !=0:
               iPaintBeg=MAX(0,iVertPos+ps.rcPaint.top/Globalvariable1.global_cyChar)
            num=Globalvariable1.global_int_displayHaveMaxLinesInClient
            if Globalvariable1.global_cyChar!=0:
               iPaintEnd=min(num-1,iVertPos+ps.rcPaint.bottom/Globalvariable1.global_cyChar)

            print("字符宽度:",Globalvariable1.global_cxChar)
            systemMetricsDicObject=systemMetricsDic1.systemMetrics()
            # 要显示的内容在按照字体高度为一行计算有多少行
            if Globalvariable1.global_int_displayHaveMaxLinesInClient==0:
                Globalvariable1.global_int_displayHaveMaxLinesInClient=systemMetricsDicObject.leng()
                print("输出显示内容具有多少行:",Globalvariable1.global_int_displayHaveMaxLinesInClient)
            if Globalvariable1.global_cxChar>0:

                for i in range(systemMetricsDicObject.leng()):

                    y=Globalvariable1.global_cyChar*(i-Globalvariable1.global_int_VerticalScrollCurrentPosition)
                    x=Globalvariable1.global_cxChar *(1-Globalvariable1.global_int_HorizontalScrollCurrentPosition)
                    #输出索引常量名
                    gdi32.TextOutW(hdc,x,y,systemMetricsDicObject.dicByIndex[i]["label"],len(systemMetricsDicObject.dicByIndex[i]["label"]))
                    #输出索引常量描述  x位置向右偏移约Globalvariable1.global_cxCaps*22
                    gdi32.TextOutW(hdc, x+Globalvariable1.global_cxCaps*44, y,
                                   systemMetricsDicObject.dicByIndex[i]["describle"],
                                   len(systemMetricsDicObject.dicByIndex[i]["describle"]))
                    value=user32.GetSystemMetrics(systemMetricsDicObject.dicByIndex[i]["index"])
                    # print("输出得到的结果:",value)
                    #右对齐
                    gdi32.SetTextAlign(hdc,win32con.TA_RIGHT|win32con.TA_TOP)
                    gdi32.TextOutW(hdc,x+Globalvariable1.global_cxCaps*44+40*Globalvariable1.global_cxChar,y,str(value),len(str(value)))
                    #恢复左对齐输出
                    gdi32.SetTextAlign(hdc, win32con.TA_LEFT | win32con.TA_TOP)


            rect=win32gui.GetClientRect(hwnd)
            win32gui.DrawTextW(hdc,"hello中国",len("hello中国"),rect,win32con.DT_SINGLELINE | win32con.DT_CENTER | win32con.DT_VCENTER)
            # win32gui.ReleaseDC(hwnd,hdc)
            #----------------任务1
            # user32.MoveWindow(cvHwnd, 0, 0, rect[2], rect[3], True)
            # endregion

            # region Description  客户区中间绘制一条直线
            lCyClient=Globalvariable1.global_cyClient
            lCxClient=Globalvariable1.global_cxClient
            gdi32.MoveToEx(hdc,0,lCyClient//2,None)
            gdi32.LineTo(hdc,lCxClient,lCyClient//2)
            # endregion

            NUM=1000
            pointsArray=structure1.POINT *NUM
            #实例化数组
            points=pointsArray()
            i=0
            for point in points:
                point.x=int(i * lCxClient /NUM)
                point.y=int((lCyClient/2) * (1-math.sin(2*math.pi * i/NUM)))
                i=i+1
            for p in points:
                print("查看数组真实值:",p.x,p.y)
            gdi32.Polyline(hdc,points,NUM)

            user32.EndPaint(hwnd,ps)
            return 0
        case win32con.WM_NCPAINT:
            print("这是非客户区消息")


        case win32con.WM_SHOWWINDOW:
            if debug:
                print("收到一个WM_SHOWWINDOW显示窗口消息,通常由调用ShowWindow函数产生")
                return 0
        case win32con.WM_SYSCOMMAND:
            if debug:
                print("注意!!!收到一个系统命令,通常不要返回,继续让消息传给系统处理:否则属于屏蔽系统命令,WM_SYSCOMMAND消息编号是:",msg," ",hex(msg),"wParam的值是:",wParam,"  lParam的值是:",lParam)

        case win32con.WM_LBUTTONDOWN:
            if debug:
                print("你单击了鼠标左键,消息编号是:",msg," ",hex(msg),"wParam的值是:",wParam,"  lParam的值是:",lParam)
            return 0
        case win32con.WM_RBUTTONDOWN:
            if debug:
                print("你单击了鼠标右键,消息编号是:",msg," ",hex(msg),"wParam的值是:",wParam,"  lParam的值是:",lParam)
            return 0
        case win32con.WM_MOUSEMOVE:
            if debug:
                pass
                # print("你正在移动鼠标,消息编号是:",msg," ",hex(msg),"wParam的值是:",wParam,"  lParam的值是:",lParam)
            return 0
        case win32con.WM_MBUTTONDOWN:
            if debug:
                print("你单击了鼠标中键,消息编号是:",msg," ",hex(msg),"wParam的值是:",wParam,"  lParam的值是:",lParam)
            return 0
        case win32con.WM_LBUTTONDBLCLK:
            if debug:
                print("你双击了鼠标左键,消息编号是:",msg," ",hex(msg),"wParam的值是:",wParam,"  lParam的值是:",lParam)
            return 0
        case win32con.WM_KEYDOWN:
            if debug:
                print("你按下了键盘键,消息编号是:", msg, " ", hex(msg), "wParam的值是:", wParam, "  lParam的值是:", lParam)
            return 0
        case win32con.WM_VSCROLL:
            #wParam低位字是通知码 比如SB_LINEUP SB_LINELEFT  SB_ENDSCROLL等  高位字是拖动滚动框时的当前位置
            #当鼠标放在滚动框上按住鼠标 移动滚动框就会产生SB_THUMBTRACK和SB_THUMBPOSITION通知码消息和滚动消息
            #在wParam低位字为SB_THUMBTRACK时 wParam高位字就是拖动滚动框时的当前位置 该值位于滚动条范围值之间
            #如果wParame低位字是SB_THUMBPOSITION时 wParam的高位字就是用户释放鼠标键后滚动框的最终位置 如果不调用
            #SetScrollPos来处理SB_THUMBTRACK或SB_THUMBPOSITION消息 用户释放鼠标后 滚动框会迅速调回原来位置
            # region Description  垂直滚动条事件
            si.cbSize=ctypes.sizeof(si)
            si.fMask=win32con.SIF_ALL

            user32.GetScrollInfo(hwnd,win32con.SB_VERT,ctypes.byref(si))
            Globalvariable1.global_int_VerticalScrollCurrentPosition=si.nPos
            #查看滚动条通知码
            match LOWORD(wParam):
                case win32con.SB_TOP:
                    si.nPos=si.nMin
                case win32con.SB_BOTTOM:
                    si.nPos=si.nMax
                case win32con.SB_LINEUP:  #按向上滚动按钮
                    si.nPos -=1

                case win32con.SB_LINEDOWN:
                    si.nPos += 1
                case win32con.SB_PAGEUP:
                    si.nPos -=si.nPage
                case win32con.SB_PAGEDOWN:
                    si.nPos +=si.nPage
                case win32con.SB_THUMBPOSITION:
                    si.nPos=si.nTrackPos
                case _:
                    pass

            si.fMask=win32con.SIF_POS
            user32.SetScrollInfo(hwnd,win32con.SB_VERT,ctypes.byref(si),True)
            user32.GetScrollInfo(hwnd,win32con.SB_VERT,ctypes.byref(si))

            if(si.nPos != Globalvariable1.global_int_VerticalScrollCurrentPosition):
                 a=Globalvariable1.global_cyChar
                 b=Globalvariable1.global_int_VerticalScrollCurrentPosition
                 user32.ScrollWindow(hwnd,0,a * (b-si.nPos),None,None)
                 user32.UpdateWindow(hwnd)
            # endregion
            return 0
        case win32con.WM_HSCROLL:
            # wParam低位字是通知码 比如SB_LINEUP SB_LINELEFT  SB_ENDSCROLL等  高位字是拖动滚动框时的当前位置
            # 当鼠标放在滚动框上按住鼠标 移动滚动框就会产生SB_THUMBTRACK和SB_THUMBPOSITION通知码消息和滚动消息
            # 在wParam低位字为SB_THUMBTRACK时 wParam高位字就是拖动滚动框时的当前位置 该值位于滚动条范围值之间
            # 如果wParame低位字是SB_THUMBPOSITION时 wParam的高位字就是用户释放鼠标键后滚动框的最终位置 如果不调用
            # SetScrollPos来处理SB_THUMBTRACK或SB_THUMBPOSITION消息 用户释放鼠标后 滚动框会迅速调回原来位置
            # region Description  水平滚动条事件
            si.cbSize = ctypes.sizeof(si)
            si.fMask = win32con.SIF_ALL

            user32.GetScrollInfo(hwnd, win32con.SB_HORZ, ctypes.byref(si))
            Globalvariable1.global_int_HorizontalScrollCurrentPosition = si.nPos
            # 查看滚动条通知码
            match LOWORD(wParam):
                case win32con.SB_LEFT:
                    si.nPos = si.nMin
                case win32con.SB_RIGHT:
                    si.nPos = si.nMax
                case win32con.SB_LINELEFT:  # 按向上滚动按钮
                    si.nPos -= 1

                case win32con.SB_LINERIGHT:
                    si.nPos += 1
                case win32con.SB_PAGELEFT:
                    si.nPos -= si.nPage
                case win32con.SB_PAGERIGHT:
                    si.nPos += si.nPage
                case win32con.SB_THUMBPOSITION:
                    si.nPos = si.nTrackPos
                case _:
                    pass

            si.fMask = win32con.SIF_POS
            user32.SetScrollInfo(hwnd, win32con.SB_HORZ, ctypes.byref(si), True)
            user32.GetScrollInfo(hwnd, win32con.SB_HORZ, ctypes.byref(si))

            if (si.nPos != Globalvariable1.global_int_HorizontalScrollCurrentPosition):
                a = Globalvariable1.global_cxChar
                b = Globalvariable1.global_int_HorizontalScrollCurrentPosition
                user32.ScrollWindow(hwnd, 0, a * (b - si.nPos), None, None)
                user32.UpdateWindow(hwnd)
            # endregion
            return 0


        case  win32con.WM_DESTROY:

            user32.PostQuitMessage(0)
            if debug:
               print("程序终止")
            return 0

    return win32gui.DefWindowProc(hwnd, msg, wParam, lParam)


def cancelWindowCaptionBar(hwnd):

    dwStyle = win32api.GetWindowLong(hwnd, win32con.GWL_STYLE)
    dwStyle ^= win32con.WS_MINIMIZEBOX  # 设置窗体取消最小化按钮
    dwStyle ^= win32con.WS_MAXIMIZEBOX  # 设置窗体取消最大化按钮
    dwStyle ^= win32con.WS_DLGFRAME  # 设置窗体取消标题栏边框
    # dwStyle &= ~(win32con.WS_SIZEBOX)     #取消调整大小
    win32api.SetWindowLong(hwnd, win32con.GWL_STYLE, dwStyle)  # 设置新的风格

className = 'MyWindowClass'
#---------第一步   初始化类结构-python版本和C语言版本有一定的不同 某些域没有cbClsExtra-----------------------------------------
#---------窗口类的作用就是定义窗口的一般性特征 或者通用特征
# region Description  第一步声明类 根据类以便创建窗口
wndClass = win32gui.WNDCLASS()
wndClass.cbWndExtra=0
wndClass.style = win32con.CS_HREDRAW | win32con.CS_VREDRAW | win32con.CS_DBLCLKS  #每当窗口水平方向或垂直方向尺寸发生改变后 要完全刷新窗口
wndClass.lpfnWndProc = windowProc                           #这个过程要处理基于这个窗口类创建的所有窗口的全部消息  使用函数名 实际引用提供指向函数的指针
wndClass.hInstance = win32gui.GetModuleHandle(None)         #程序的实例句柄
wndClass.hCursor = win32gui.LoadCursor(None, win32con.IDC_ARROW)    #使用预定义图标 第一个参数为None  使用自定义图片 第一个参数为程序的实例句柄
wndClass.hbrBackground =  win32con.COLOR_WINDOW     #win32gui.GetStockObject(win32con.WHITE_BRUSH) 或者获取图像对象#将窗口客户区边界设置为指定颜色
wndClass.lpszClassName = className
# endregion

#--------第二步  注册类---------------------------------------------
wndClassAtom = win32gui.RegisterClass(wndClass)   #因为python中变量名就是结构体的地址 无须像C语言使用取地址运算符&

if(wndClassAtom==0):
        print("注册失败")
        sys.exit(0)
# print("注册结果",wndClassAtom)
#-------第三步  创建程序主窗口-------------------------------------------------
#窗口具有垂直和水平滚动条win32con.WS_HSCROLL=0x00100000  in32con.WS_VSCROLL=0x00200000L
hwnd = win32gui.CreateWindow(className, "我的窗口", win32con.WS_OVERLAPPEDWINDOW | 0x00100000 |0x00200000,
                             100, 100, 500, 500, None, None, win32gui.GetModuleHandle(None), None)

#---------第四步 显示并更新窗口
user32.ShowWindow(hwnd, win32con.SW_SHOW) #产生一个WM_SIZE消息
user32.UpdateWindow(hwnd)  #产生一个WM_PAINT消息


#-------第五步 创建消息结构体并建立消息循环 -------------------------------
msg = ctypes.wintypes.MSG()

wParam=None
lparam=None
#手动调用一次回调函数 python调试时中不自动执行创建初始化
# windowProc(hwnd,win32con.WM_CREATE,0,0)

#-------自己使用函数调用---------------------------
user32.SendMessageA(hwnd,win32con.WM_CREATE,wParam)
hdc=user32.GetDC(hwnd)
testString="测试文字\n又是一个"
#注意 参数涉及字符串的函数可能都有ASCII版本和Unicode版本
gdi32.TextOutW(hdc,0,0,testString,len(testString))

user32.ReleaseDC(hwnd,hdc)

#测试使用格式化函数wsprintfW
# region Description  测试函数使用
user32.wsprintfW(pStringBuffer,"this is %d test %d,%d",ctypes.c_int32(5).value,ctypes.c_int32(7).value,ctypes.c_int32(5).value)
print("缓冲字符串:",pStringBuffer)
s=""
for i in pStringBuffer:
    # print(i,end='')
    if i != b'\x00':
        s=s+i.decode('utf-8')
print(s)
    # print(i.decode('utf-8'),end="")
print("测试全局变量的Globalvariable1.global_cxChar值",Globalvariable1.global_cxChar)
# endregion

#第六步 自动执行消息队列  msg由操作系统自动生成 传递给你的程序
while user32.GetMessageW(ctypes.byref(msg), None, wParam, lparam) != 0:
    user32.TranslateMessage(ctypes.byref(msg))
    user32.DispatchMessageW(ctypes.byref(msg))
 

演示效果:

  • 27
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值