wxPython 笔记
安装
Win7 / Win10
直接通过 pip install wxpython 安装
Ubuntu18.04 / Ubuntu 20.04
在Linux下的安装会稍微麻烦, 可以参考官网上的说明 https://wxpython.org/pages/downloads/
因为存在不同的环境, 以及Gtk2, Gtk3, 所以没有针对各个发行版直接可用的pip whl文件, 通过 pip install wxpython的话, 实际上会去下载源码到本地编译安装, 参考 https://wxpython.org/blog/2017-08-17-builds-for-linux-with-pip/index.html 其中What You Need部分, 在Ubuntu下需要安装这些包
# 安装依赖
sudo apt install make gcc libgtk-3-dev ibgstreamer-gl1.0-0 freeglut3 freeglut3-dev python3-gst-1.0 libglib2.0-dev ubuntu-restricted-extras libgstreamer-plugins-base1.0-dev # 从国内源下载, 之后会自动启动编译
pip3 install -i https://pypi.mirrors.ustc.edu.cn/simple/ wxpython
但是这个编译时间非常长, 在i5 2520M 下编译需要将近一个小时.
还好官方有提供Ubuntu的whl文件, 可以直接安装, 从 https://extras.wxpython.org/wxPython4/extras/linux/gtk3/ubuntu-20.04/ 直接下载20.04的whl文件, 在本地通过pip安装. 对于Ubuntu18.04存在不同的python版本, 选择不同的cp36, cp37, cp38
pip3 install -U -f wxPython-4.1.0-cp38-cp38-linux_x86_64.whl wxPython
在安装的过程中, 会检查numpy并下载安装
在后续运行代码时, 如果遇到 libSDL2-2.0.so.0: cannot open shared object file: No such file or directory 错误, 则需要安装 libsdl2-2.0-0
sudo apt install libsdl2-2.0-0
打包生成可执行文件
在Ubuntu下安装pyinstaller, 然后在项目目录下执行命令
$ pip3 install pyinstaller
$ pyinstaller v2subform.py
36 INFO: PyInstaller: 3.6
36 INFO: Python: 3.6.9
36 INFO: Platform: Linux-4.15.0-99-generic-x86_64-with-Ubuntu-18.04-bionic
37 INFO: wrote /home/milton/PycharmProjects/python-tools/v2sub/v2subform.spec
38 INFO: UPX is not available.
40 INFO: Extending PYTHONPATH with paths
['/home/milton/PycharmProjects/python-tools/v2sub',
'/home/milton/PycharmProjects/python-tools/v2sub']
40 INFO: checking Analysis
...
8115 INFO: Building COLLECT COLLECT-00.toc
8803 INFO: Building COLLECT COLLECT-00.toc completed successfully.
最后生成的结果在dist目录下, 如果运行时不希望出现命令行, 可以加上 --noconsole 参数
在用下面的代码测试时, 发现生成的结果文件非常大, 有263M, 其中wx目录就占了200多M,
$ ll -h wx
total 199M
-rwxr-xr-x 1 milton milton 18M May 7 11:16 _adv.cpython-36m-x86_64-linux-gnu.so*
-rwxr-xr-x 1 milton milton 156M May 7 11:16 _core.cpython-36m-x86_64-linux-gnu.so*
-rwxr-xr-x 1 milton milton 14M May 7 11:16 _grid.cpython-36m-x86_64-linux-gnu.so*
-rwxr-xr-x 1 milton milton 12M May 7 11:16 _html.cpython-36m-x86_64-linux-gnu.so*
-rwxr-xr-x 1 milton milton 795K May 7 11:16 siplib.cpython-36m-x86_64-linux-gnu.so*
这么大的发布文件, 在日常和商业上都是非常不适用的, 这就仅作为一个尝试吧.
代码示例
#!/usr/bin/python3
# -*- coding: UTF-8 -*- import base64
import json
import os
import subprocess
import requests
import wx
import wx.grid as grid class MainFrame(wx.Frame):
def __init__(self, parent, title):
super().__init__(parent=parent, title=title, size=(665, 450))
self.panel = MainPanel(self)
self.Show(True) class MainPanel(wx.Panel):
def __init__(self, parent):
super().__init__(parent=parent)
self.configs = self.loadConfig() sizer1 = wx.BoxSizer(wx.VERTICAL)
self.text_ctrl = wx.TextCtrl(self, -1)
width, height = self.text_ctrl.GetSize().Get()
# Make it shows the URL completely, weird bug of TextCtrl
self.text_ctrl.SetSize((500, height))
sizer1.Add(self.text_ctrl, 0, wx.ALL | wx.EXPAND, 5)
self.main_grid = grid.Grid(self)
self.main_grid.CreateGrid(0, 6)
# Forbid row height changes
self.main_grid.EnableDragRowSize(False)
# Global forbid cell editing
self.main_grid.EnableEditing(False)
# Selection of the entire rows only
self.main_grid.SetSelectionMode(grid.Grid.GridSelectRows)
# Hide row header
self.main_grid.HideRowLabels()
# Set column headers
self.main_grid.SetColLabelSize(grid.GRID_AUTOSIZE)
self.main_grid.SetLabelFont(wx.Font(10, wx.FONTFAMILY_ROMAN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) self.main_grid.SetColLabelValue(0, 'ID')
self.main_grid.SetColSize(0, 30)
self.main_grid.SetColMinimalWidth(0, 30) self.main_grid.SetColLabelValue(1, 'Name')
self.main_grid.SetColSize(1, 180) self.main_grid.SetColLabelValue(2, 'Address')
self.main_grid.SetColSize(2, 180)
self.main_grid.SetColLabelValue(3, 'Port')
self.main_grid.SetColSize(3, 40)
self.main_grid.SetColLabelValue(4, 'Network')
self.main_grid.SetColSize(4, 60)
self.main_grid.SetColLabelValue(5, 'Test')
self.main_grid.SetColSize(5, 40)
self.main_grid.Bind(grid.EVT_GRID_SELECT_CELL, self.onSingleSelect)
sizer1.Add(self.main_grid, 1, wx.ALL | wx.EXPAND, 5) sizer2 = wx.BoxSizer(wx.VERTICAL)
btn_import = wx.Button(self, label='Import')
btn_import.Bind(wx.EVT_BUTTON, self.onImport)
sizer2.Add(btn_import, 0, wx.ALL | wx.EXPAND, 5) btn_ping = wx.Button(self, label='Ping')
btn_ping.Bind(wx.EVT_BUTTON, self.onPing)
sizer2.Add(btn_ping, 0, wx.ALL | wx.EXPAND, 5) btn_select = wx.Button(self, label='Select')
sizer2.Add(btn_select, 0, wx.ALL | wx.EXPAND, 5) sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(sizer1, 1, wx.EXPAND, 0)
sizer.Add(sizer2, 0, wx.EXPAND, 0)
self.SetSizer(sizer) # load subscribe url
self.text_ctrl.SetValue(self.configs['subscribe_url'])
# load nodes into grid
self.loadGrid() def loadGrid(self):
rows = self.main_grid.GetNumberRows()
if rows > 0:
self.main_grid.DeleteRows(0, rows)
for k in self.configs['nodes']:
node = self.configs['nodes'][k]
self.main_grid.AppendRows(1)
pos = self.main_grid.GetNumberRows() - 1
self.main_grid.SetCellValue(pos, 0, k)
self.main_grid.SetCellValue(pos, 1, node['ps'])
self.main_grid.SetCellValue(pos, 2, node['add'])
self.main_grid.SetCellValue(pos, 3, str(node['port']))
self.main_grid.SetCellValue(pos, 4, node['net']) self.main_grid.SetFocus() def onSingleSelect(self, event):
print('You selected row:{}, col:{}'.format(event.GetRow(), event.GetCol()))
event.Skip() def loadConfig(self):
this_path = os.path.dirname(__file__)
conf_path = os.path.join(this_path, 'v2subform.conf')
if not os.path.exists(conf_path):
open(conf_path, 'w+') with open(conf_path, 'r') as conf_file:
try:
configs = json.load(conf_file)
print('Loaded configs from file: {}'.format(conf_path))
except json.decoder.JSONDecodeError:
print('File {} is not a valid config file'.format(conf_path))
configs = None if configs is None or len(configs) == 0:
print('The configuration is empty, please input the necessary information')
configs = {
'subscribe_url': '',
'local_port': 1080,
'nodes' : []
}
with open(conf_path, 'w') as conf_file:
json.dump(configs, conf_file, indent=2) return configs def onImport(self, event):
subscribe_url = self.text_ctrl.GetValue()
if not subscribe_url:
dialog = wx.MessageDialog(self, 'You didn\'t input subscribe URL', 'Error', wx.OK)
dialog.ShowModal()
dialog.Destroy()
return rows = self.main_grid.GetNumberRows()
if rows > 0:
self.main_grid.DeleteRows(0, rows) self.configs['subscribe_url'] = subscribe_url
print('Subscribed URL: {}\nLocal port:{}\n'.format(self.configs['subscribe_url'], self.configs['local_port']))
print('Reading server nodes... ', end='')
node_strings = base64.b64decode(requests.get(self.configs['subscribe_url']).content).splitlines()
print('Done')
nodes = {}
for i in range(len(node_strings)):
node = json.loads(base64.b64decode(bytes.decode(node_strings[i]).replace('vmess://', '')))
print('[{:>3}] {:25} {:30}:{}'.format(i, node['ps'], node['add'], node['port']))
nodes[str(i)] = node
self.configs['nodes'] = nodes this_path = os.path.dirname(__file__)
conf_path = os.path.join(this_path, 'v2subform.conf')
with open(conf_path, 'w') as conf_file:
json.dump(self.configs, conf_file, indent=2)
self.loadGrid() def onPing(self, event):
rows = self.main_grid.GetSelectedRows()
if rows is None:
dialog = wx.MessageDialog(self, 'You didn\'t select any row', 'Error', wx.OK)
dialog.ShowModal()
dialog.Destroy()
return
id = self.main_grid.GetCellValue(rows[0], 0)
node = self.configs['nodes'][id]
result = subprocess.run(['ping', node['add']], capture_output=True)
if not result is None:
dialog = wx.MessageDialog(self, result.stdout, 'Result', wx.OK)
dialog.ShowModal()
dialog.Destroy()
return if __name__ == '__main__':
app = wx.App(False)
frame = MainFrame(None, 'Small Editor')
app.MainLoop()
wxPython 笔记的更多相关文章
- 收集了一些python的文章
来自: 戴铭 2010-08-31 17:52:31 newthreading - safer concurrency for Python 安全并发(1回应) http://www.starming ...
- wxPython学习笔记(初识)
今天正式开始学习wxPython,基于对类的不熟悉,理解有点生硬,但还是做了些笔记. 1.是什么组成了一个wxpython程序? 一个wxpython程序必须有一个application(wx.App ...
- Python学习笔记:wxPython(GUI图形用户界面)
wxPython是一套基于Python的第三方GUI插件,可用Python制作丰富的图形化界面程序. 安装:pip install wxPython 或者 网站下载安装https://pypi.org ...
- wxPython学习笔记(三)
要理解事件,我们需要知道哪些术语? 事件(event):在你的应用程序期间发生的事情,它要求有一个响应. 事件对象(event object):在wxPython中,它具体代表一个事件,其中包括了事件 ...
- wxPython学习笔记(二)
如何创建和使用一个应用程序对象? 任何wxPython应用程序都需要一个应用程序对象.这个应用程序对象必须是类wx.App或其定制的子类的一个实例.应用程序对象的主要目的是管理幕后的主事件循环. 父类 ...
- wxPython学习笔记(一)
创建最小的空的wxPython程序 frame = wx.Frame(parent=None, title='Bare') frame.Show() return True app = App() a ...
- python学习笔记十四:wxPython Demo
一.简介 wxPython是Python语言的一套优秀的GUI图形库,允许Python程序员很方便的创建完整的.功能键全的GUI用户界面. wxPython是作为优秀的跨平台GUI库wxWidgets ...
- wxPython学习笔记1
wxpython介绍: wxPython 是 Python 语言的一套优秀的 GUI 图形库,允许 Python 程序员很方便的创建完整的.功能键全的 GUI 用户界面. wxPython 是作为优 ...
- wxPython学习笔记
------------恢复内容开始------------ 学习wxPython 资料 1.wxpython wiki Getting started with wxPython https://w ...
- 阶段性放弃 wxPython 前的总结
为了实现一个管理本地电子书的程序,搞了一段时间 GUI,使用 wxPython. 实在难以适应和习惯,也搞不出什么太好看的效果. 最不能忍受的是,多线程处理能力太弱.遂决定放弃 GUI. 放弃之前,整 ...
随机推荐
- DC-设计和工艺数据-02
在 compile之前保存ddc设计文件 check design - 检查文件的连接性和物理性 check design之后可以将未映射的网表写出,如果是几十万级的RTL,如果不写出,设置约束出现问 ...
- ASIC 功能验证SVTB
System Verilog进行验证是可以不综合的 发现DUT中的功能问题 预备知识:Linux/verilog/gvim System Verilog学习目录 System Verilog Test ...
- [转帖]Oracle数据库开启NUMA支持
NUMA简介 NUMA(Non Uniform Memory Access Architecture,非统一内存访问)把一台计算机分成多个节点(node),每个节点内部拥有多个CPU,节点内部使用共有 ...
- 【转帖】15.JVM栈帧的内部结构
目录 1.栈中存储的是什么? 2.栈的运行原理 1.栈中存储的是什么? 1.每个线程都有自己的栈,栈中存储的是栈帧. 2.在这个线程上正在执行的每个方法都各自对应一个栈帧.方法与栈帧是一对一的关系. ...
- [转帖]新一代垃圾回收器ZGC的探索与实践
1. 引入 1.1 GC之痛 很多低延迟高可用Java服务的系统可用性经常受GC停顿的困扰. GC停顿指垃圾回收期间STW(Stop The World),当STW时,所有应用线程停止活动,等待GC停 ...
- CentOS创建vsftp进行读写操作的简单方法
1. 安装vsftpd yum install epel-release yum install vsftpd 2. 进入系统设置简单进行处理 注意 user_list 是不允许访问的列表. [roo ...
- 【验证码逆向专栏】数美验证码全家桶逆向分析以及 AST 获取动态参数
声明 本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码,抓包内容.敏感网址.数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关! 本文章未经许 ...
- 【K哥爬虫普法】辛苦钱被中间商抽走八成,还因此锒铛入狱
我国目前并未出台专门针对网络爬虫技术的法律规范,但在司法实践中,相关判决已屡见不鲜,K 哥特设了"K哥爬虫普法"专栏,本栏目通过对真实案例的分析,旨在提高广大爬虫工程师的法律意识, ...
- Asp .Net Core 部署在阿里云Centos上 :使用Docker部署
参照 https://www.cnblogs.com/xiaxiaolu/p/9973631.html 运行环境 使用SecureCrt连接服务器 1.阿里云ECS 4核 16 GiB 8Mbps 带 ...
- 小白学k8s(11)-k8s中Secret理解
理解Secret 什么是Secret Secret的类型 Opaque Secret Opaque Secret的使用 将Secret挂载到Volume中 挂载的Secret会被自动更新 将Secre ...