按照计划开始Python3学习最后2个主题:简单的数据库连接和多线程。目标也很简单,能够实现一些简单的任务,需要时能够完成自己的工作处理就行。至于流行的Python来做网络爬虫等估计可预见的时间内用不到,暂时不学。原来准备学习的通信,也不学了。后面会用数据库和excel配合,完成一个实操的小工具,然后Python的学习就暂时告一段落了。虽然懂得不多,但基本算入门了吧。
前面用Timer实验了一个例子程序。还算比较简单。直接贴代码上来。后面再逐步完善。
import time,datetime import threading,timer
def timer_start(): print("I'm timer1111,") t=threading.Timer(1,test_func,("Parameter1",)) #启动一个新线程 t.start() while True: time.sleep(5) strTime = datetime.datetime.now().strftime('%Y-%M-%D %H:%M:%S') print("thread main:",strTime) def test_func(msg1): print("I'm test_func,",msg1) while True: time.sleep(2) strTime = datetime.datetime.now().strftime('%Y-%M-%D %H:%M:%S') print("thread 2",strTime)
两个线程同时守候运行。
http://blog.sina.com.cn/s/blog_c22e36090102x3o2.html
from PyQt5.QtSql import (QSqlDatabase, QSqlQuery, QSqlRelation, QSqlRelationalDelegate, QSqlRelationalTableModel, QSqlTableModel)
app = QApplication(sys.argv) filename = os.path.join(os.path.dirname(__file__), "assets.db") create = not QFile.exists(filename) db = QSqlDatabase.addDatabase("QSQLITE") db.setDatabaseName(filename) if not db.open(): QMessageBox.warning(None, "Asset Manager", ("Database Error: {0}" .format(db.lastError().text()))) sys.exit(1)
def createFakeData(): import random print("Dropping tables...") query = QSqlQuery() query.exec_("DROP TABLE assets") query.exec_("DROP TABLE logs") query.exec_("DROP TABLE actions") query.exec_("DROP TABLE categories") QApplication.processEvents() print("Creating tables...") query.exec_("""CREATE TABLE actions ( id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, name VARCHAR(20) NOT NULL, description VARCHAR(40) NOT NULL)""") query.exec_("""CREATE TABLE categories ( id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, name VARCHAR(20) NOT NULL, description VARCHAR(40) NOT NULL)""") query.exec_("""CREATE TABLE assets ( id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, name VARCHAR(40) NOT NULL, categoryid INTEGER NOT NULL, room VARCHAR(4) NOT NULL, FOREIGN KEY (categoryid) REFERENCES categories)""") query.exec_("""CREATE TABLE logs ( id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL, assetid INTEGER NOT NULL, date DATE NOT NULL, actionid INTEGER NOT NULL, FOREIGN KEY (assetid) REFERENCES assets, FOREIGN KEY (actionid) REFERENCES actions)""") QApplication.processEvents() #填充数据 print("Populating tables...") query.exec_("INSERT INTO actions (name, description) " "VALUES ('Acquired', 'When installed')") query.exec_("INSERT INTO actions (name, description) " "VALUES ('Broken', 'When failed and unusable')") query.exec_("INSERT INTO actions (name, description) " "VALUES ('Repaired', 'When back in service')") query.exec_("INSERT INTO actions (name, description) " "VALUES ('Routine maintenance', " "'When tested, refilled, etc.')") query.exec_("INSERT INTO categories (name, description) VALUES " "('Computer Equipment', " "'Monitors, System Units, Peripherals, etc.')") query.exec_("INSERT INTO categories (name, description) VALUES " "('Furniture', 'Chairs, Tables, Desks, etc.')") query.exec_("INSERT INTO categories (name, description) VALUES " "('Electrical Equipment', 'Non-computer electricals')") today = QDate.currentDate()
query.prepare("INSERT INTO assets (name, categoryid, room) " "VALUES (:name, :categoryid, :room)") logQuery = QSqlQuery() logQuery.prepare("INSERT INTO logs (assetid, date, actionid) " "VALUES (:assetid, :date, :actionid)") assetid = 1
(给name、category、room赋值)
query.bindValue(":name", name) query.bindValue(":categoryid", category) query.bindValue(":room", room) query.exec_()
logQuery.bindValue(":assetid", assetid) when = today.addDays(-random.randint(7, 1500)) # when=when.toString() logQuery.bindValue(":date", when.toString("yyyy-MM-dd")) logQuery.bindValue(":actionid", ACQUIRED) logQuery.exec_()
print("Assets:") query.exec_("SELECT id, name, categoryid, room FROM assets " "ORDER by id") categoryQuery = QSqlQuery() while query.next(): id = query.value(0) name = str(query.value(1)) categoryid = query.value(2) room = str(query.value(3)) categoryQuery.exec_("SELECT name FROM categories " "WHERE id = {0}".format(categoryid)) category = "{0}".format(categoryid) if categoryQuery.next(): category = str(categoryQuery.value(0)) print("{0}: {1} [{2}] {3}".format(id, name, category, room)) QApplication.processEvents()
model完成数据源的数据读写;视图view会向model请求打算显示的数据项;对于每个数据项,view都会把数据项个painter传递给委托(delegate),要求绘制该项。 相应地,如果用户开始编辑操作,view会要求delegate提供一个Editor,用户接收了编辑后,更新的数据就会回传给Model。模型中的每个数据项都可以通过唯一的QModelIndex加以识别。每个QModelIndex独有三个重要属性:行、列和父对象。列表只用到行;表格用到行、列;分层模型如树会用到全部三个属性。
一些PyQt的窗口部件,例如QListWidget、QTableWidget、QTreeWidget,都带有模型和委托的视图。可以通过简便项窗口部件方便地进行控制;QListView、QTableView、QTreeView,则需要与外部窗口部件一起工作,或者使用内置的QStringListModel、QDirModel、QSqlTableModel一起工作,这些统称为自定义模型。
QTableWiget的操作为例,很简单,就是表格操作,每个格子就是一个Item。
可参考:QTableWidget详解(样式、右键菜单、表头塌陷、多选等) - 莫水千流 - 博客园 https://www.cnblogs.com/zhoug2020/p/3789076.html
例子中,Qt UserRole就是组件角色,在复杂系统中使用的比较多,原因也很简单,系统复杂,为了组件区分方便。 在Qt中很多类是可以给他添加角色值的,比如说QComboBox中的setItemData()与QStandardItemModel中的setData()这两个函数,都是在Index位置上添加角色值。在图书的实例中和id就是hash值绑定,作为索引使用。
写入时设置:item.setData(Qt.UserRole, id(ship)) 使用时首先获取,然后使用:currentTableShip() { return self.ships.ship( item.data(Qt.UserRole))} ship = self.currentTableShip() 相应的python3+PyQt5验证代码都可以在下面博客找到: 【原创】python3+PyQt5 使用三种不同的简便项窗口部件显示数据_basisworker_新浪博客http://blog.sina.com.cn/s/blog_c22e36090102x3l0.html
需要说明,实际验证结果:QTimer.singleShot(0, self.initialLoad)实际上可以去掉,直接调用self.initialLoad()就可以,否则会刚运行起来就死掉。 另外,前面哪部分就是ships.pyw的内容,不需要再去找原书的源代码了,对应要简单修改一下代码。2018/06/23
针对已有的QAbstractModel,要实现的方法:
1)对实现只读模型很有必要的方法 data() rowCount() columnCount() headerData()
用于只读型的委托,唯一必须重新实现的是paint()
对于可编辑型的,必须重新实现createEditor() setEditorData() commitAndCloseEditor()
self.tableView2 = QTableView()
tableLabel2.setBuddy(self.tableView2)
self.tableView2.setModel(self.model)
self.tableView2.setItemDelegate(ships.ShipDelegate(self)) #数据的展示和编辑由delegate来完成
实际工作时,只要用户确认了编辑结果,编辑器(delegate)的数据就必须回写到模型中,模型通知视图,该项内容已经改变,而显示该项的视图会要求对显示的数据进行更新。
GUI快速编程这本书中的例子比较简单,对照起来,自己刷新数据的简便项窗口部件方式觉得更好一些,有复杂逻辑的估计还是用自定义模型的MVC更好吧。如果你实现的是一个最基本的取表格数据,写到表格中显示的,那就基本只要关联设置一下,其它什么都不用做。
相应的python3+PyQt5验证代码都可以在下面博客找到:
【原创】python3+PyQt5 使用自定义委托控制数据项的展示和编辑 _basisworker_新浪博客http://blog.sina.com.cn/s/blog_c22e36090102x3m5.html
【原创】python3+PyQt5 使用自定义模型保存数据并通过不同视图形式展示数据_basisworker_新浪博客http://blog.sina.com.cn/s/blog_c22e36090102x3ly.html。。。。。。
#binding events with slots
self.assetView.selectionModel().currentRowChanged.connect(self.assetChanged) #行改变链接到self.assetChanged
。。。。。。
def assetChanged(self, index):
if index.isValid():
record = self.assetModel.record(index.row())
#通过id将asset 和log关联起来
id = record.value("id")
self.logModel.setFilter("assetid = {0}".format(id))
else:
self.logModel.setFilter("assetid = -1")
#self.logModel.reset() # workaround for Qt <= 4.3.3/SQLite bug
#self.logModel.beginResetModel()
self.logModel.select()
self.logView.horizontalHeader().setVisible( self.logModel.rowCount() > 0)
if PYQT_VERSION_STR < "4.1.0":
self.logView.setColumnHidden(ID, True)
self.logView.setColumnHidden(ASSETID, True)
#self.logModel.endResetModel()