利用Python自带GUI调用C语言库实现混合编程。
Python原生GUI库,款平台支持比较好,功能一般。普通的测试Demo足够了。 不同版本python中库的首字母大小写可能有所不同,导入模块的时候需要注意。
有人对常用的GUI库做了个简单的归纳
- Tkinter: python内置的GUI框架,使用TCL实现,python中内嵌了TCL解释器,使用它的时候不用安装额外的扩展包,直接import,跨平台。不足之处在于UI布局全靠代码实现,只有15种常用部件,显示效果简陋。
- Wxpython:用得比较广泛,跨平台,C++编写,需要安装扩展模块;文档少,遇到问题不好解决,代码布局控件,不直观。
- Pygtk: python对GTK+GUI库的封装,在linux平台上运行的比较好,需要安装扩展模块,在windows下的兼容性有一些问题。
- pyqt:QT原本是诺基亚的产品,源码用C++写的,python对QT的包装,跨平台,本地显示效果,根据系统决定,在win7下就是win7的显示效果;pyqt与qt的函数接口一致,qt开发问的那个丰富,所以pyqt开发文档也比较丰富;控件丰富,函数/方法多,拖曳布局;方便打包成二进制文件;GPL协议,商业程序需要购买商业版授权
- pyside:诺基亚的亲儿子,python对QT的封装,安装扩展模块,跨平台,与pyqt的API一样,LGPL协议,新软件可以是私有的,代码布局
- Kivy: 针对多点触控程序,智能手机平板等,也可以在没有触屏功能的系统上,全平台支持;使用python和cython(python和c语言的接口)编写;中文支持差,需要自己下载中文库并且制定路径。 作者:田同学的小迷妹儿 链接:https://www.jianshu.com/p/ef71566ff8bb 来源:简书 简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
ctypes库能把python类型和C类型数据一一对应起来
python根据动态库的符号表能识别到库内的函数,并根据传递的参数类型判断参数偏移地址从而使用C语言库。
以下是python3.6.5官方手册内的类型转换关系,python的类型果然更加无脑些~
ctypes type | C type | Python type |
---|---|---|
c_bool | _Bool | bool (1) |
c_char | char | 1-character bytes object |
c_wchar | wchar_t | 1-character string |
c_byte | char | int |
c_ubyte | unsigned char | int |
c_short | short | int |
c_ushort | unsigned short | int |
c_int | int | int |
c_uint | unsigned int | int |
c_long | long | int |
c_ulong | unsigned long | int |
c_longlong | __int64 or long long | int |
c_ulonglong | unsigned __int64 or unsigned long long | int |
c_size_t | size_t | int |
c_ssize_t | ssize_t or Py_ssize_t | int |
c_float | float | float |
c_double | double | float |
c_longdouble | long double | float |
c_char_p | char * (NUL terminated) | bytes object or None |
c_wchar_p | wchar_t * (NUL terminated) | string or None |
c_void_p | void * | int or None |
写一个C库并编译
头文件test.h(只是编译库给Python用,其实可以不用头文件)
typedef struct
{
int int_result;
double double_result;
} RESULT_STRUCT;
int download();
int add(int a,int b,double *c );
int initialize();
int terminate();
int get_status();
int get_result(RESULT_STRUCT* result);
库实现test.c
#include <stdio.h>
#include <stdlib.h>
#include "test.h"
int download()
{
printf("CDLL Download\n");
return 0;
}
int add(int a,int b,double *c )
{
*c=a+b;
printf("CDLL %d + %d = %lf \n",a,b,*c);
return 0;
}
int initialize()
{
printf("CDLL initialize\n");
return 0;
}
int terminate()
{
printf("CDLL terminate\n");
return 0;
}
int get_status()
{
printf("CDLL get_status\n");
return 0;
}
int get_result(RESULT_STRUCT* result)
{
printf("CDLL get_result\n");
result->double_result=0.123;
result->int_result=1;
return 0;
}
本地是用code::blocks 17.12 自带的Mingw32-gcc编译的release版本
#!/usr/bin/env python
# -*- coding: utf8 -*-
#Author : lous
from tkinter import *
import sys
import os
from ctypes import *
from struct import *
#Author : lous
class RESULT_STRUCT(Structure):
_fields_ = [("int_result", c_int),
("double_result", c_double)]
class Application(Frame):
def load_dll(self):
"""载入动态库"""
self.libtst = CDLL('libpython_clib.dll')
def app_relase(self):
"""退出界面时释放资源"""
self.relase_resource()
self.quit()
def relase_resource(self):
"""释放申请的资源"""
pass
def footprint(self, message):
self.result_text.insert(1.0,"\n"+message+"\n")
def result_clear(self):
self.result_text.delete(1.0,END)
def download(self):
"""调用download"""
rtn=self.libtst.download()
self.footprint("libtst.download()")
def add(self):
"""调用add"""
c=c_double(0)
rtn=self.libtst.add(1,2,byref(c))
self.footprint("libtst.add() c = %f" %(c.value))
def initialize(self):
"""调用initialize"""
rtn=self.libtst.initialize()
self.footprint("libtst.initialize()")
def terminate(self):
"""调用terminate"""
rtn=self.libtst.terminate()
self.footprint("libtst.terminate()")
def get_result(self):
"""调用get_result"""
result=RESULT_STRUCT()
rtn=self.libtst.get_result(byref(result))
self.footprint("get_result %d %lf" %(result.int_result,result.double_result))
def createWidgets(self):
#root frame
self.root_frame=Frame(self).grid(sticky=N+S+E+W)
#输入frame
self.input_frame=Frame(self.root_frame)
self.input_frame.grid(row=0,column=0,sticky=N+S+E+W)
self.create_input_frame()
#子 frame
self.sub_frame=Frame(self.root_frame)
self.sub_frame.grid(row=0,column=1,sticky=N+S+E+W)
self.create_sub_frame()
#输出框
self.output_frame=Frame(self.root_frame)
self.output_frame.grid(row=2,column=0,columnspan=2,sticky=N+S+E+W)
self.create_output_frame()
def create_input_frame(self):
self.position_sb=Spinbox(self.input_frame)
self.position_sb.grid(row=0,column=1)
self.position_label=Label(self.input_frame,text="Positon m")
self.position_label.grid(row=0,column=0)
self.velocity_sb=Spinbox(self.input_frame)
self.velocity_sb.grid(row=1,column=1)
self.velocity_label=Label(self.input_frame,text="Velocity m/s")
self.velocity_label.grid(row=1,column=0)
self.acceleration_sb=Spinbox(self.input_frame)
self.acceleration_sb.grid(row=2,column=1)
self.acceleration_label=Label(self.input_frame,text="acceleration m/s^2")
self.acceleration_label.grid(row=2,column=0)
self.jerk_sb=Spinbox(self.input_frame)
self.jerk_sb.grid(row=3,column=1)
self.jerk_label=Label(self.input_frame,text="Jerk m/s^3")
self.jerk_label.grid(row=3,column=0)
self.djerk_sb=Spinbox(self.input_frame)
self.djerk_sb.grid(row=4,column=1)
self.djerk_label=Label(self.input_frame,text="DJerk m/s^4")
self.djerk_label.grid(row=4,column=0)
def create_sub_frame(self):
#initialize
self.initialize_btn = Button(self.sub_frame)
self.initialize_btn["text"] = "initialize"
self.initialize_btn["command"] = self.initialize
self.initialize_btn.grid(row=0)
#terminate
self.terminate_btn = Button(self.sub_frame)
self.terminate_btn["text"] = "terminate"
self.terminate_btn["command"] = self.terminate
self.terminate_btn.grid(row=1)
#get_result
self.get_status_btn = Button(self.sub_frame)
self.get_status_btn["text"] = "get_result"
self.get_status_btn["command"] = self.get_result
self.get_status_btn.grid(row=2)
#add
self.add_btn = Button(self.sub_frame)
self.add_btn["text"] = "add"
self.add_btn["command"] = self.add
self.add_btn.grid(row=3)
def create_output_frame(self):
self.result_text=Text(self.output_frame,height=8)
self.result_text.grid(columnspan=2)
##滚动条
#self.result_scrollbar=Scrollbar(self.output_frame)
#self.result_scrollbar.grid(row=8,column=1,sticky=N+S)
#self.result_scrollbar.config(command=self.result_text.yview)
#self.result_text.config(yscrollcommand=self.result_scrollbar.set)
self.result_clear_btn = Button(self.output_frame)
self.result_clear_btn["text"] = "Clear"
self.result_clear_btn["command"] = self.result_clear
self.result_clear_btn.grid(row=1,column=1)
#创建退出
self.QUIT = Button(self.output_frame)
self.QUIT["text"] = "QUIT"
self.QUIT["command"] = self.app_relase
self.QUIT.grid(row=1)
def __init__(self, master=None):
Frame.__init__(self, master)
#master.geometry("1280x720")
self.load_dll()
#initialize_resource()
self.createWidgets()
root = Tk()
HRIS = Application(master=root)
HRIS.master.title("Test Demo")
HRIS.mainloop()
root.destroy()
C库在终端打印的信息
CDLL 1 + 2 = 3.000000
CDLL get_result
CDLL terminate
CDLL initialize
Tkinter界面
左侧的输入在这个示例中没有使用上,只是显示tkinter有输入、输出和按钮等常规功能。若需要更进一步的功能,可以查找tkinter的官方文档。
如果功能比较复杂,可以考虑PyQt(最起码界面操作简单好看)