初次接触WFP的一些感受

前言

学习一项新东西之前,先对他有一个简单慨括性的认识时十分由必要的,如果只是一股脑儿的扎进去,往往得达不到你想要的效果。这是我以前经常会犯的错误,花费了大量的精力纠缠于细枝末节,结果却收获甚少。所以这一次为了学会使用WPF,我先到网上查找了很多资料关于WPF的资料和其他开发这对它的评价。

俗话说的好,磨刀不误砍柴工,尽管我还一句代码都没有写,但是通过查找的这些信息,我却已经对WPF设计的目的、优缺点以及其使用范围有了一很清晰的认识。

WPF是什么

在没有了解它之前,我一直都傻傻的搞不清C#和WPF的关系,现在终于懂了,简单来说WPF只是一套界面开发系统,只是由于主要用C#开发,所以常常被一起提及。

稍微官方一点,WPF是Windows Presentation Foundation的缩写, 中文译为“Windows呈现基础”,是微软推出的基于Windows Vista的用户界面框架,由 .NET Framework 3.0 开始引入,与 Windows Communication Foundation及 Windows Workflow Foundation并行为新一代 Windows操作系统以及 WinFX 的三个重大应用程序开发类库。

以上是参考百度官方的解释,听起来很高大上,实际上用WPF也是能够做出很炫的界面来的。但是从微软推出来这么多年了,却很少商业的软件使用它,也证明了它实际上还是有很多不足之处,或者合适的适用范围不算大,其他领域有更优秀的替代者。

WPF的特点

大家谈WPF的时候总是对比WinForm,可惜我WinForm了没有做过,只能对比一下老掉牙的MFC了。

  1. 使用了比较强大的xaml语言来设计界面

    回想一下MFC是怎么开发界面的:当然是直接拖放控件啦。通过可视化的界面设计器设计ui,VS则同步将你的修改翻译成文本文件,来记录窗口和它上面控件的位置和大小。但是也仅仅于此,MFC使用的这种界面记录语言对界面的控制表达能力太若了,除了了记录控件的固定的位置、大小,以及一些简单的固有属性,我真不清楚它还有什么其他作用。不过说起来,这个文本文件本来就不算是一个有比较清晰的语法规范的语言,而且在实际使用时,基本上不会用到它,而是直接拖放界面。总的来说用MFC的界面设计器来设计界面,可以说除了直观一点外,没有什么其他好处,所以我在做MFC时,宁愿直接用C++代码来实现,这样至少保证我的程序是一个完整的整体,大部分代码都能在我自己的控制范围内,不会出现因为界面某次操作错误而导致程序无法编译,然后还没法去排查错误的问题。

    而在WPF中就不一样了,同样的可视化设计,但是它的核心却在它的设计脚本语言上。它采用的界面设计语言xaml是XML的扩展,可以完成非常复杂而精细的界面控制。就我个人的初步体验来看,它是非常类似于用html来设计网页。如界面元素的布局、排版、对齐,终于可以不再花费大量的时间去手动实现了,基本上界面的控制都可以用xaml来控制。由于xaml是本质上是XML,遵循的XML的标准,这使得它有清晰、标准的语法结构,这样使它的控制力和可读性都使非常强的。

    另外,在独立控制界面的基础上,xaml还有一些与后台通信的方式,这使得WPF设计界面即保持了很强的独立性,有可以方便与后台保持交互。

  2. 数据驱动

    对与刚刚接触WPF的我,数据驱动是让我映像最深刻的一个特性。把控件的数据源和数据绑定,直接操作数据,界面就会跟随更新,这就让数据和界面分离开来了,而且将原来可能本来使对复杂界面的变成了直接对数据的操作,一下子让程序简单了很多。通常对复杂的数据会抽象成模型,便于做统一的操作。

    实际上这样的特性我在Qt中已经有所接触。Qt里使用的是MVC模式,WPF则使用的是MVVC模式,由于加入了多个V(ViewMode)层,让它有了更好的特性,如:双向绑定技术,界面和数据源绑定后,任意一方改变,另一方都会自动跟随改变。至于MFC,就完全看不到这种东西,要操作数据,都是通过传统的方法去做:获取控件本身,然后再获取其数据,然后再修改修改数据。而MFC不同的控件获取的方法可能不一样或者有是条件和限制的或是需要传入很多其他复杂的参数,这导致它的操作相当的繁琐。

  3. 一些缺点

    • 性能差,内存占用量大
    • 基于.net,在很多低版本的版本的windows上不能使用,其他平台就不用更不说了。
Compartir

MySQL的使用简介

为什么使用数据库

就个人体会而言,使用数据库相比使用普通的文件存储,主要有以下三点好处:

  1. 存储简单强大

    数据库有通用标准SQL的语句来控制数据的存储,存储的数据相对规范,而普通文件存储,则需要自己每次都要编写代码,且存储数据的格式随意。

  2. 强大的数据管理

    对我而言数据库对数据强大的管理系统是区别于一般文件存储的最大区别,数据采用的都是高度优化的代码,不管是查找、添加还是删除速度都是非常快的,实现这些仅仅只需几条简单的SQL语句就可以,而普通的文件存储想要达到这样的效果要花费的代价就太大太大了。另外数据库,还有一些高级的功能,如支持事务处理。

  3. 数据共享于权限管理

    数据库可以通过网络为每个用户提供数据服务,还可以为这些用户分配不同的权限,从而实现数据的共享与数据的安全管理。

简单来说,如果数据只是一些无规律的信息,或是一些数据量非常小不需要过多操作的信息的话,使用普通的文件存储可能会更简单。但是如果数据的信息量大,经常需要去查询或修改的话,那就使用数据来管理就要方便得多了。

MySQL中MyISAM和InnoDB的优缺点

MySQL支持多种存储引擎,其中最常用的是:MyISAM和InnoDB

  1. MyISAM

    MyISAM是MySQL中最早出现的引擎,其执行速度快,但是不支持事务。MyISAM又可以分为三种子类型:

    • 静态MyISAM: 表中各个数据列长度固定,是默认的类型,其执行效率非常高
    • 动态MyISAM: 表中有有如varchar、xxxtext等类型的字段,其每条记录的长度不一,执行效率不如静态的,内存中也有可能造成许多碎片,需要经常用optimize tabel命令或优化工具整理碎片。
    • 压缩MyISAM: 以上两种表通过myisamchk工具压缩后生成,这种表可以减少表占用的存储空间,但是压缩后不能被修改,读取时也需要先进行解压操作。
  2. InnoDB

    InnoDB是MySQL后面支持的引擎,它支持了事务、行级锁机制、外键约束的等高级的功能,但是它的执行效率比MySQL要低。

    由于支持事务操作,InnoDB可以很方便的执行回滚操作,具体操作:

    1. 关闭自动提交:set autocommit=0;
    2. 开启事务: begin;
    3. 执行语句
    4. 正确提交:commit; 错误则回滚: rollback

为什么使用事务

在MySQL中InnoDB是支持事务的,使用事务的最大的好处是,由于事务的原子特性可以将一系列操作当作一个整体来执行,执行成功后提交,执行失败可以回滚到事务开始前,可以避免数据库由于在执行中途错误而无法返回到原来的初始状态的情况。

使用事务时,需要注意以下两点:

  1. 关闭自动提交

    MySQL时默认打开自动提交的,所以要使用事务,需要先关闭自动提交:set autocommit = 0

  2. 某些SQL语句会导致事务的回滚失败

    某些SQL语句如创建表\库、管理用户等,当执行完成后,会隐式的commit操作,在事务中包含有这些语句的,一旦出错,也无法回滚到事务执行的初始状态。在设计事务时不应该包含这些语句。这样的语句主要分以下三类:

    • DDL语句:ALTER DATABASE、ALTER EVENT、ALTER PROCEDURE、ALTER TABLE、ALTER VIEW、CREATE TABLE、DROP TABLE、RENAME TABLE、TRUNCATE TABLE等
    • 修改MYSQL架构的语句:CREATE USER、DROP USER、GRANT、RENAME USER、REVOKE、SET PASSWORD
    • 管理语句:ANALYZE TABLE、CACHE INDEX、CHECK TABLE、LOAD INDEX INTO CACHE、OPTIMIZE TABLE、REPAIR TABLE

为什么使用引索

数据表的引索就像书的目录,为数据表创建引索,可以大大提高查找的执行效率。索引常常被用来快速找出在一个列上用一特定值的行,没有引索,MySQL不得不首先以第一条记录开始并然后读完整个表直到它找出相关的行,表越大,花费时间越多。所以经常用WHERE语句做条件判断的列较适合创建引索。

创建一个或多个引索的SQL语句为:

1
ALTER TABLE tbl_name ADD INDEX(col1,col2,...)

特殊的创建表的主键时,就会自动创建主键列引索,它数据唯一引索。

参考

  1. 浅谈MySql的存储引擎(表类型)
    :http://www.cnblogs.com/lina1006/archive/2011/04/29/2032894.html
Compartir

VS创建C#控制台和WPF工程介绍

前言

尽管我前面使用过C#,但是从来没有系统的学习过,就更不用说WPF了,我甚至一直以来都没有弄清楚它们两者之间的关系。刚好目前公司有项目是C#做的,所以借机将C#相关的知识系统性的整理一遍。本文以控制台程序和WPF程序为例,简单的介绍用VS搭建C#工程的组织结构。

控制台程序工程结构

使用VS(我的是VS2015)新建项目,选择“控制台程序”,创建一个基于控制台的项目,其资源管理组织结构如下:

CSharp工程结构

  1. AssemblyInfor.cs

    这个文件主要用来存放资源信息(如版本、版权等),和资源文件比较类似。一般情况我们很少直接修改其源文件,而是通过项目的属性进入“应用程序”->“程序集信息”,在其中修改,如下图所示:

    程序信息

  2. App.Config

    应用程序的配置文件,以XML格式编写,类似与C++的ini文件,不管是外部还是C#源代码都可以对其进行操作。编译后,在生成的目标文件夹下,它的名字为“程序名.exe.config”,里面的内容和App.config一样。

  3. Program.cs

    这个是C#源文件,包含了程序的入口函数“Mian”。

WPF程序工程结构

WPF是Windows Presentation Foundation的缩写,是微软新一代图形系统,一套API函数库,运行在.NET Framework 3.0及以上版本下,与早期的GDI+/GDI不同,WPF是基于DirectX引擎的,可以支持GPU硬件加速。

使用VS新建项目,选择“WPF应用程序”,创建一个WPF项目,其资源管理组织结构如下:

WPF工程结构

如上图所示,和控制台程序一样,WPF工程也包括AssemblyInfor.cs和App.config文件,他们的作用和控制台程序中的一样。

  1. Resources.resx

    这是WPF程序的资源文件,可以添加字符串、图像等资源文件。在它下面有名为“esources.resx.cs”由VS根据它自动生成的cs文件。

  2. Settings.settings

    配置文件,和App.Config不一样,它在编译后就内嵌到代码中了,外部无法操作。在Settings.settings中定义的配置它有两种作用范围:User和Application。User为运行时可以更改,Application为运行时不可更改。在它的下面也有VS自动生成的“Settings.settings.cs”文件。

  3. App.xaml和App.xaml.cs

    App.xaml是WPF应用的定义入口的地方,它并不是一个严格的xml文件,它所有的定义都会由编译器翻译成最后的代码,其中StartUri定义WPF主窗体文件。实际上在WPF的应用中可以没有App.xaml文件,它的功能是可以全部交给后台来做的,这就和控制台程序一样,需要在Main函数中实现。

    下图为网友总结的App.xaml默认内容的说明:

    app.xaml文件说明

    App.xaml.cs文件会定义继承于应用程序类的App类,它是窗口应用的中心类。

  4. MainWindow.xaml和MainWindow.xaml.cs

    MainWindow.xaml为WPF主窗体的设计文件,在VS中可以直接用窗体设计器来设计,而MainWindow.xaml.cs则是对应主窗体的类。

Compartir

MySQL的常用SQL语句和简单存储过程

前言

本文主要是汇总记录,我自己在工作中经常使用的,MySQL数据库的SQL语句,而不是这些SQL语句的说明详解。如果需要快速了解常用MySQL操作,可以查看其他的网友的教程,如:21分钟 MySQL 入门教程

本文第一部分是单独的SQL语句整理,第二部分为组合这些SQL语句的存储过程写法的介绍。

MySQL常用的语句

  1. 登陆数据库系统

    • 本地: mysql -u [username] -p [password]
    • 远程: mysql -h [ip] -P [port] -u [username] -p [password]
  2. 库的操作

    • 创建数据库: create database [databasename]
    • 显示数据库: show databases
    • 进入数据库: use [databasename]
    • 删除数据库: drop database if exists [databasename]
  3. 表的操作

    • 创建表:create table [databasename] (col1 bigint not null,col2 varchar(15),col3 double precision,col4 bigint,primary key (col1)) ENGINE=InnoDB
    • 显示表: show tables
    • 删除表: drop table [tablename] if exists ORDERS
    • 获取列信息: desc [columnname]
    • 清空表: truncate table [tablename];
    • 复制表的结构到新表: create [newtable] like [oldtable]
    • 复制表的数据到新表: insert into [table1] (col1, col2, …) select col1, col2, … from [table2] where [condition]
    • 插入数据时覆盖已有数据: replace into [table1] (col1, col2, …) select col1, col2, … from [table2] where [condition]
    • 插入数据时忽略已有数据: insert ignore into [table1] (col1, col2, …) where [condition]
    • 重命名表: alter table [tablename] rename [newtablename]
    • 增加一列: alter table [tablename] add column [columnname] [type] default [default]
    • 修改列名: alter table [tablename] change [oldlolname] [newcolname] [type]
    • 删除一列: alter table [tablename] drop [colname]
  4. 主键操作

    • 设置主键: alter table [tablename] add primary key([colname])
    • 删除主键: alter table [tablename] drop primary key
    • 设置自增字段(前提是该列为一个key): alter table tb change [colname] [colname] int(10) not null auto_increment=1
    • 删除自增字段: alter table [tablename] change [colname] [colname] int(10)
  5. 记录

    • 插入记录: insert [table1] (col1,col2…) [table2] (val1,val2…)
    • 删除记录: delete from [tablename] where [condition]
    • 查找记录: select [columnname] from [tablename] where [condition]
    • 修改字段值: update [tablename] set [col]=[val],… where [condition]
  6. 用户的操作

    • 添加用户: insert into mysql.user(Host,User,Password) values(“localhost”,”test”,password(“1234”));
    • 删除用户: delete from user where User=’test’ and Host=’localhost’
    • 分配所有权限: grant all privileges on testDB.* to test@localhost identified by ‘1234’
    • 刷新权限: flush privileges
    • 修改密码: mysqladmin -u root -p password [newpassword]
  7. 参数与状态

    • 查看配置参数(以wait_timeout为例): show variables like ‘%wait_timeout%’
    • 查看状态: show status
    • 设置参数: set [paraName] = [value]
    • 设置全局参数(重启后仍然会失效): set global [paraName] = [value]

存储过程

  1. 引用系统变量

    • 全局变量: @@global.[varname]
    • 局部变量: @@session.[varname] 或者 @@local.[var_name]

    如果在变量前面没有级别限定,则优先会话级别的变量。

  2. 声明或定义变量

    变量的作用域只能在begin…end块中,不区分大小写

    1
    declare [val] [type];
  3. 创建存储

    注意begin和end后无分号,不能有return

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    create procedure [procedurname]
    (
    [param] [type],[param] [int],.....
    )
    begin
    ...;
    ...;
    ...;
    end
    }
  4. 调用存储过程

    1
    call [procedurname]([param,...])
  5. 删除存储过程

    1
    drop procedure if exists [proceduename]
  6. 实例

    delimiter $$命令就是将语句的结束符从分号修改成其他符号,这里指的是$$为结尾

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    delimiter $$
    drop procedure if exists wk;
    create procedure wk()
    begin
    declare i bigint;
    set i = 17011210000;
    while i < 17011213999 do
    insert ignore into mini_s(pn) values(i);
    set i = i+1;
    end while;
    end $$

    call wk();
Compartir

用XAMPP提供网络mysql数据库服务

XAMPP简介

XAMPP是一个集合了多种服务的软件包,其中的字母A、M、P、P分别Apache、Mysql、PHP、Perl,除了这几个最重要的软件包外,它还包含了如FTP、OpenSSL等更多的服务和工具。XAMPP是跨平台的,能够在Windows、Linux、Mac OS等多种操作系统上使用。独立的安装和配置Apache服务器不是很容易的事,而如果还要在其上添加Mysql、PHP、Perl的功能就更加困难了,而使用XAMPP则可以大大的简化安装流程。

XAMPP的安装(Windows平台)

XAMPP官方网站为:http://www.xampps.com/,在上面选择下载对应的操作系统版本。因为我的服务器跑的是Windows操作系统,所以我下载的是Windows版本。

对于Windows的平台,XAMPP官方提供两种形式的安装方式:一是通过普通的安装文件安装,另一种则是直接解压软件包即可。下载地址:https://sourceforge.net/projects/xampp/files/XAMPP%20Windows/,选择对应的版本和安装文件下载。

注意,使用解压方式安装XAMPP,如果是解压到根目录,可以尝试直接启动服务,如果不是的话,需要先先运行一下“setup_xampp.bat”进行配置。另外如果解压是双重目录(如 d:/xampp/xampp ),也需要运行“setup_xampp.bat”。

XAMPP的配置常用修改项

使用XAMPP来提供和管理数据库,需要用到两个服务,第一个就是MySQL,另一个就是Apache。MySQL提供数据库服务,Apache提供管理数据库工具phpMyAdmin工具所需的http服务。一般情况下保持XAMPP的默认配置就可以直接开启这两个服务器,如果无法启动服务则需要考虑修改相应的配置参数

  1. Apache端口修改

    一般情况使用默认端口80是没有问题的,但是也有可能和其他应用服务(如ISP)发生冲突,如果出现端口冲突那么就需要修改Apache的端口,在XAMPP控制面板的Apache栏,点击“Config”,选择Apache,修改http.conf文件,将Listen和ServerName Localhost两项修改为没有被占用的端口号。

  2. phpMyAdmin设置

    新安装的XAMPP的MySQL root密码是空的,需要手动为其添加密码,通过phpMyAdmin的“用户账户”对用户进行操作可以很方便的操作。

    当当root的修改密码修改后,需要修改phpMyAdmin的配置,否则将无法登陆。在XAMPP控制面板的Apache栏,点击“Config”,选择phpMyAdmin,在打开的config.inc.php文件中修改配置项“$cfg[‘Servers’][$i][‘password’]=”,将其设为修改的密码

  3. 修改MySQL的端口号

    修改MySQL的端口号在my.ini文件中,客户端和服务器的端口号都在这里修改。

MySQL图形化工具

使用命令行可以登陆到本地或者远程的MySQL服务器,并能通过SQL语句进行各种数据库操作。但是为了操作方便,我们是可以利用图形化的工具来操作的。服务器端可以使用XAMPP自带的phpMyAdmin,而客户端可以使用其他第三方客户端工具,如HeidiSQL(插入新列时,界面显示有些问题,可能需要刷新多次才能显示修改的数据)。

参考

  1. 百度百科:http://baike.baidu.com/item/XAMPP
  2. 浅谈MySql的存储引擎(表类型)
    :http://www.cnblogs.com/lina1006/archive/2011/04/29/2032894.html
Compartir

机器学习——梯度下降算法的理解

前言

近些年来机器学习、神经网络、深度学习越来越火热,从去年的AlphaGo的大放异彩到这几天和最顶尖人类棋手连战豪取60连胜的神秘棋手Master(现已经被证实为AlphGo的升级版),这些技术让我们这些普通人也真正感受到了人工智能的强大。一直以来我都式作为旁观的身份来仰望着这些神奇有趣技术,虽然它们无时无刻不吸引着我,但是我总是觉得自己能力够而不敢去触碰。

最近在看《科学的极致——漫谈人工智能》这本科普书,书中介绍了很多人工智能邻域有趣的问题和技术,终于在认识到了人工智能领域众多技术之后,我开始尝试学习当前深度学习学术界最著名的学者之一的Andrew Ng教授在斯坦福大学的《机器学习》公开课。

《机器学习》课程设计到很多知识点,但是我这里不会讲课程上的知识一一全部记录,因为在网上一搜,发现又网友的都在期blog上分享了学习笔记,而且都做得相当不错,而在斯坦福大学的网站上也能找到该课程的讲义资料,所以会记录下网友中整理的比较好的笔记文章的链接,而我自己的笔记讲主要集中在自己对这些知识的理解上。

监督学习

《机器学习》第二课知识点笔记:http://blog.csdn.net/xiaocainiaodeboke/article/details/50371986

《机器学习》课程的第一个大的部分是 监督学习。其实一直来我都有听说过“监督学习”、“非监督学习”这些名词,但是完全搞不懂是什么意思。听过《机器学习》的第二课之后,终于有了一点认识。现在我的理解是:对与要解决的问题,所提供的输入的数据都是知道其实际的真实结果的,而监督学习的方式是让计算机找出的解决问题的方法与实际的结果尽量吻合。而“非监督学习”则是对于输入的数据不知道其实际结果,而需要计算机自己发现和挖掘规律,来形成解决方法。它们的差异主要是输入的数据实际结果是否已知。

这样解释是有点抽象,具体一点,监督学习可以分为两类问题:回归问题和分类问题。回归问题是在已知的数据和结果平面上做拟合曲线,而分类问题则是用曲线划分结果不同的数据区域,而这些都是在已知数据对应的真正的结果后才能做的。

在监督学习中,通常的方法是:假设一个结果的拟合曲线表达式,用输入的数据去验证,得到计算结果和实际结果之间的差值;然后通过上一次的结果改进方法,再次验证,一直到计算的结果和实际结果接近;

那么怎么判断计算的结果已经是最优呢?这里一般会累加输入数据的计算结果和真实结果的方差和来判断。所以当求得方差和的最小值时,其对应的表达式就是最优的。

梯度下降算法

为了求得方差和最小,一个最简单最古老的算法就是—— 梯度下降法。其原理是:计算方差和表达式变化率最大的负方向,沿着这个方向前进就能走到平面最低点,而最低点对应方差和的最小值。

特殊的以线性拟合为例,如果只研究输入数据的一个属性和结果的关系,那么我们需要得到的式一个一元一次方程y=ax+b,未知量为系数a和b。那么其方差和表达式就可以看成一个关于a、b的二元二次方程,用三维图像可以画出其对应的就是空间里的一个曲面,沿着两个2维度找到负梯度最大的方向,当梯度为0时,就是这个平面的最小值。

使用梯度下降算法的步骤是:先设定一个初值(如上例子中的a和b都为0),找到这个初值点的最大负梯度方向,然后向这个方向上移动,得到一个新的点,同样求取这一点的最大负梯度方向,依次迭代,直到最大负梯度为0,这时候的结果(a和b)就是最优的。

梯度下降算法的特点:

  • 每次迭代都需要把所有的数据都重新遍历一遍,当数据量很大时,计算比较费的时。
  • 每次迭代的步进度是变化的,当接近最小点时步进需要很小,否则就会走过。
  • 初值选取对结果有很大影响,应为其找的时局部最优解。

随机梯度下降法

如上所说,如果数据量很大时,使用全部的数据的梯度下降来求最优解是计较耗时的,着方法被称之为批梯度下降算法。为了简化这个算法,人们有在其基础上改进得到了随机梯度下降算法。

随机梯度下降算法,每次只使用一个数据,同样确定一个初始点,计算它的样本中任意一个数据的方差表达式的最大负梯度,然后向最大负梯度的方向移动,然后在在样本中任取另外一个点,做同样的操作,依次迭代。通常在数据量很大的情况下,只用迭代一小部分数据就可以求得一个相对较优得解。

正规方程

在课程中Andrew Ng还讲解了求取最优解得另一种方式——正规方程,使用矩阵的形式推导,而不用像梯度下降那样每次都需要去迭代了,直接使用矩阵推导的最优解的表达式不一步到位。可惜矩阵相关的知识都已经忘记的差不多了,所以推导的过程完全听不懂。

显然,对于样本数据量大、每一个数据的属性变量多时,用正规方程去求解更有优势。关于梯度下降算法和正规表达式的比较,有网友总计:http://blog.csdn.net/sd9110110/article/details/53558821

Compartir

python工作线程与界面的交互

常见的场景

在界面的程序设计中,一旦需要执行的任务操作需要很长时间才能完成时,往往需要一个单独的线程来独立负责,如果直接放在界面的主线程中,则会导致界面消息长时间不能得到响应,界面卡死。而一旦使用到多线程则,则需要考虑诸如线程间的通信、线程的同步等问题,在这里仅针对工作线程与界面线程交互的问题,这个数据属于通信问题,不过对象比较特殊,且时在python的环境下。

问题描叙

在我的项目中,使用Qt做界面,用python的threading库创建工作线程,在工作线程中需要完成一系列的任务,当每个部分完成后,需要和界面进行交互,如最简单的处理进度和当前步骤结果信息的在界面上的输出。而本文主要是总结以下,怎样在工作线程中控制界面的显示或控件设置问题。

解决方案

解决方案有如下几种:

  1. 在线程中获取,界面窗体对象进行直接操作

    这是最简单直接的方法,这个方案的关键在于窗体对象的获取,我们可以有多种方法来获取窗体对象:

    • 通过全局变量传递
    • 将线程的回调函数设为有参数的,创建时通过窗体对象作为参数传递进去
    • 通过对操作系统的API调用,来查找需要的窗口对象(在python中没有实验过)

    当获得了窗体对象后,就可以任意调用其中的成员函数和成员变量了。但是当我使用PyQt5的的时候,这种方法时有问题的。

    通过获取的窗体对象,读取或者改写与界面无关的成员时,没有问题;但是一旦涉及到UI控件的一些写操作时久有可能出问题,如:在工作线程使用QTextEdit的setText()函数里面改变QTextEdit控件的显示文字时,程序会卡死。不过这里说的是可能,使用诸如改变窗口的setWindowTitle()设置窗口名称、改变QLabel的文字、改变QLineEdit的内容,都没有出现问题。

    后面到网上搜索,发现QT文档上是不允许这样跨线程修改UI控件这样的操作的,所以我觉得这种方法可以用来获取窗口类成员的值比较合适,如果要对界面做修改则需要考虑其他办法。

  2. 使用通过发送信号实现

    由于在工作线程中直接操作界面控件可能会出现一些问题,所以比较标准的做法是通过发送信号来实现通信。

    在MFC中可以先自定义消息,然后用sendmessage或postmessage来将消息发送给对应的界面窗体。而在Qt中则可以使用信号与槽机制来实现。实现方法如下:

    • 第一步,导入QObject模块和pyqtSignal函数
    1
    from PyQt.QtCore import QObject
    • 第二步,创建一个继承与QObject的类,其成员为信号,通过使用pyqtSignal函数来创建自定义信号
    1
    2
    3
    class UpdataUI(QObject):
    UpdateTextSignal = pyqtSignal(str)
    UpdateResultSignal = pyqtSignal(str, str)
    • 第三步,实例化信号类,将信号connnect到界面操作函数作为的槽,如下代码initUserSignal函数的参数是传入的窗体类对象
    1
    2
    3
    4
    def initUserSignal(wnd):
    update = UpdataUI()
    update.UpdateTextSignal.connect(wnd.appendText)
    update.UpdateResultSignal.connect(wnd.setTestResult)
    • 第四步,在需要使用槽函数的地方发送其连接的消息
    1
    2
    update.UpdateTextSignal.emit('\nRun: OK')
    update.UpdateResultSignal.emit('True', '\nCheak MD5: OK')
Compartir

树莓派开发板的简单使用以及开发环境搭建

基本介绍

我买回的新树莓派开发板就只有板子和说明书,其他的东西都要自己准备:

  • 供电: 一般手机USB充电线
  • 存储: 8G或8G以上内存卡+读卡器
  • 显示: HDMI线+显示器
  • 网络: 一般网线

烧写官方系统

对于树莓派开发板,官方提供了多种操作系统的支持,可以让开发很方便的在上面开发,下载地址:https://www.raspberrypi.org/downloads/。当然,最基本的我们使用得最多的是Raspbian系统,它是基于linux Debian的。系统需要烧写到内存卡中的,而Raspbian的解压后的文件镜像超过4G,所以我们需要8G或者以上的额内存卡。

在windows系统上可以使用Win32DiskImager或者usbImage工具来烧写,其中usbImage工具可以支持多个usb设备的同时写入。usbImage的下载地址为:http://www.osforensics.com/tools/write-usb-images.html

通过网线连接树莓派

烧写了Raspbian系统的板子,就可以通过网络连接电脑或者通过HDMI线接显示器来开发了。用通过网络连接开发板时,一般使用PuTTY工具通过ssh连接,这里有两种方法。

  1. 第一种是,将树莓派接入路由器组建的局域网

    这这种方法十分简单,在路由器上查看其ip地址,通过PuTTY连接即可

  2. 第二种是,用网线直接连接电脑

    这是针对在没有路由器的情况下,而且电脑带有有限和无线双显卡(一般笔记本都是这个配置),这是种方法是通过网络共享,让树莓派使用电脑无线网卡共享出来的网络,在这种情况下电脑作为了路由器的功能,可以让电脑有限网卡和树莓派板子处于同一网段,不过需要保持电脑有线网卡和树莓派有一方是动态分配ip的。建议将树莓派的ip设为静态ip,电脑有限网卡设为动态ip,这样每次连接树莓派,使用的ip地址就不用一直换了。

    • 第一步,修改在无线网络的属性,打开“Internet连接共享”:

    • 第二步,查找树莓派的ip地址,在cmd命令窗口种输入如下命令:

    1
    arp -a

    扫描网段

    • 第三步,使用ip地址通过ssh登陆

使用PuTTY连接树莓派,成功连接后,终端将显示登陆信息,输入用户密码登陆,登陆成功后如下图所示:

远程登陆

修改raspi-config配置

使用PuTTY远程登陆成功后,在其终端种输入:

1
sudo raspi-config

可以直接在PuTTY中显示raspi-config设置程序界面,这里面都是一些常用的基本设置,如下图所示:

raspi-config

安装远程桌面

PuTTY能够为我们提供一个文本环境,通过终端在树莓派中控制调试系统或开发应用程序。如果我们需要一个图形界面的话,那就需要外接显示器。不过还有另外一种更方便的方法,可以让你在没有显示器的情况下,通过vncserver来提供远程桌面服务。

  1. 安装tightvncserver

    在连接树莓派的PuTTY终端中输入:

    1
    sudo apt-get install tightvncserver

    确保Internet是联通的,等待它自动下载安装。

  2. 安装成功使用如下命令先设置一个密码

    1
    vncpasswd
成功后会提示是否设置view-only密码,可以不设置


  1. 输入以下命令开启vncserver服务

    1
    vncserver :1 -geometry 1200x960

    这样在树莓派上就新建了一个远程桌面,在上面的命令中1表示生成的远程桌面号,800x600表示桌面的分辨率

  2. 在PC上下载VNC的客户端VNC Viewer

    VNC Viewer作为VNC的客户端,可以连接在树莓派上的VNC服务器,并提供远程桌面的显示。官方下载地址为:https://www.realvnc.com/download/viewer/,选择合适的系统版本下载。

    打开VNC Viewer,新建一个连接,如下图所示在VNC Server栏输入树莓派的ip地址加远程桌面号,中间以冒号分割,即可开始连接了。

    VNC Viewer连接设置

    如下为连接成功,后的远程桌面示意图
    VNC Viewer显示远程桌面

利用Samba服务对windows共享文件

  1. 下载安装Samba服务

    在终端中输入以下命令来安装Samba。

    1
    sudo apt-get install samba
  2. 修改配置文件/etc/samba/smb.conf

    使用vi或者nano或者其他工具打开都可以,将/etc/samba/smb.conf文件中的[home]节中,把“read only=yes”修改为“read only=no”,然后重启samba服务:

    1
    sudo /etc/init.d/samba restart
  3. 添加用户

    如下将用户“pi”添加到samba用户中,并输入密码:

    1
    sudo smbpasswd -a pi

    这样你就可以在windows中通过ip地址:\\192.168.6.123\ 连接树莓派,然后登陆用户名和密码,来访问已经共享的文件夹。

    在window中访问树莓派的共享文佳夹

参考

  1. 无显示器无路由器无键盘无鼠标,仅靠网线直连笔记本用最简单配置玩转树莓派
  2. 树莓派教程系列6:文件共享(samba)
Compartir

用python操作MySQL数据库

怎样用python操作MySQL数据库

由于MySQL服务器以独立的进程运行,并通过网络提供对外的服务,所以需要相应的驱动来连接到MySQL的服务器,目前python中常用的两个驱动是:

  • mysql-connector-python: MySQL官方的纯python驱动,使用时import mysql.connector
  • MySQL-python: 是封装了MySQL C驱动的python驱动,使用时import MySQLdb

实际上两者的操作是十分类似的,我自己使用的是mysql connector,所以后面都以mysql connector来说明。

mysql connector安装

在mysql官网能够找到connector for python的下载页面到:http://dev.mysql.com/downloads/connector/python/

在上面找到对应的系统平台和python版本下载。windows平台的都为msi文件,直接双击运行即可。

mysql connector使用方法

mysql connector使用方法如下:

  1. 导入模块mysql connector

    1
    import mysql.connector
  2. 连接数据库

    需要服务器的ip、port、user和password等作为参数,连接时也可以直接指定数据库和数据表

    1
    conn = mysql.connector.connect(host = db_server_ip, port = db_server_port, user = db_user, passwd = db_password, db = db_database)
  3. 获取操作游标

    对mysql的大多数操作都需要用游标执行,游标相当于一个操作接口。

    1
    handle = conn.cursor()
  4. 用execute函数执行sql语句

    1
    2
    handle.execute('show tables')
    handle.execute('create table if not exists ft_status(pn varchar(15) not null, ft2 bool, ft3 bool, ft4 bool, ft5 bool, primary key (pn)) COLLATE="utf8_general_ci" ENGINE=MyISAM')
  5. 提交执行和获取执行数据

    当有执行的操作影响了数据库时,需要执行提交操作以使得执行生效

    1
    conn.commit()

    当执行的操作有返回数据时,需要用fech去获取,fech的形式有几种,如下会为获取所有数据

    1
    2
    handle.execute('select COLUMN_NAME from information_schema.columns where table_name="ft_status"')
    data = handle.fetchall()
  6. 操作完成后,需要关闭连接和游标

    1
    2
    handle.close()
    conn.close()
Compartir

用布局管理器布局Qt界面

前言

在使用Qt设计软件的界面,布局管理器是一项非常实用且方便的功能。而相比之下,在MFC里如果需要控件位置跟随窗口大小变化还需要自己实现。布局管理器控件配合Qt Designer一起使用,能够获得更好的体验,当然如果对Qt十分的熟悉,直接用代码控制也是可以的。

布局管理器的介绍

布局管理器顾名思义就是管理ui界面布局的工具,它为界面中提供一种框架,它保证即使窗口大小发生变化时,仍能然处于其中的各个界面元素按照既定的规则排列分布。在布局管理中,界面元素两个最重要的属性就是 位置大小,而布局管理器能够对其进行有效的管理,让界面元素能够跟随主窗口的尺寸,动态的调整自身的位置和大小。

在Qt中布局管理有六种,他们分别是:

  • 水平分布
  • 垂直分布
  • 使用分裂水平分布
  • 使用分裂垂直分布
  • 栅格分布
  • 表单分布

虽然六个种类看上去有点多,但是实际上可以它们分成三类:水平分布类(包括水平分布和水平分裂分布)、垂直分布类(包括垂直分布和垂直分裂分布管理)和网格分布类(包括栅格分布和表单分布)。

其中水平分布类和垂直分布类,分别会让处于其中的界面元素成水平排列和垂直排列,在其非分布的方向上只能存在一个界面元素。加入了“分裂”两字的管理器,当大小发生变化时会要求其中界面元素的在两个方向上都要有变化,而无“分裂”两字的则纸要求在非分布方向上跟随界面改变。

如下使用垂直分布和垂直分裂分布的结果:

垂直分布
垂直分裂分布

两种网格分布的管理器,能够定义多行多列网格,将界面元素放入每个格子里进行管理。我的理解是表单分布是比较特殊的栅格分布,当要管理的界面元素都是表单时用表单分布会比较方便,而栅格分布则比较通用。

布局管理器的使用

前面说过在Qt Designer中使用布局管理器是非常方便的,所以我这里只说明Qt Designer里的操作。在Qt Designer中使用布局管理器有两种方法:

  • 一是在工具栏中直接将你要使用的布局管理器托放到界面里

Qt Layouts侧边工具栏

  • 二是将给界面里的元素添加布局管理的属性

Qt Layouts右键菜单

以上这两种方法,我比较喜欢第二种,如QMainWindow和QGroupBox本身都不具有布局管理的功能,这使得放入其中得物体,都不能随窗口得大小变化而自动适应,但是通过添加布局管理功能后,就可以解决这种问题。添加方法:

选中界面元素 --> 右键弹出菜单 --> 选择“布局”菜单 --> 选择你想要得布局器


使用布局前后,再属性栏中的对比:

添加布局前
添加布局后

其他

  1. 按比例调整位置和大小

    将控件放入分布管理器,当外层窗口缩放时,默认是安比例调整分布其中的控件的位置和大小的。

  2. 设置对齐

    再默认情况下,分布管理器中是没有对齐的,我们可以通过右键菜单,选中分布管理器右键 –> Layout Alignment在Layout Alignment中添加一些对齐我们需要的对齐方式

  3. 使用spacer

    当分布管理器中的控件很少,只能占据分布管理器的一小部分,但是我又希望分布管理仍然保持一个比较的大的框架,可以在其中添加spacer控件,它只是占据控件来撑起框架,实际界面时没有作用也不会显示。另外,还可以设置spacer控件长度或者宽度为固定值,使分布管理器保持固定大小,而不跟随外层窗口改变。

spacer控件的使用

Compartir