PyQt5应用与实践

2015-01-16 19:00 by 吴秦, 69476 阅读, 5 评论, 收藏, 编辑

一个典型的GUI应用程序可以抽象为:主界面(菜单栏、工具栏、状态栏、内容区域),二级界面(模态、非模态),信息提示(Tooltip),程序图标等组成。本篇根据作者使用PyQt5编写的一个工具,介绍如何使用PyQt5构建一个典型的GUI应用。

1. 主界面

QMainWindow类提供一个有菜单条、锚接窗口(例如工具条)和一个状态条的主应用程序窗口。主窗口通常用在提供一个大的中央窗口部件(例如文本编辑或者绘制画布)以及周围菜单、工具条和一个状态条。QMainWindow常常被继承,因为这使得封装中央部件、菜单和工具条以及窗口状态变得更容易。

clip_image002

菜单栏

创建菜单的代码如下:

self.addMenu = self.menuBar().addMenu("&添加")
self.addMenu.addAction(self.addAvatarAct)
self.addMenu.addAction(self.addAvatarSetAct)
self.addMenu.addAction(self.addAvatarDecorationAct)
self.modifyMenu = self.menuBar().addMenu("&修改")
self.modifyMenu.addAction(self.modifyAvatarAct)
self.modifyMenu.addAction(self.modifyAvatarSetAct)
self.settingMenu = self.menuBar().addMenu("&设置")
self.settingMenu.addAction(self.settingAct)

其中每个菜单项,关联一个QAction,定义了图标、菜单名、回调函数、快捷键等等,这里没有设置快捷键。

self.addAvatarAct = QAction(QIcon("res/ico/addAvatar.ico"), "&Add Avatar", self, triggered=self.addAvatar)
self.addAvatarSetAct = QAction(QIcon("res/ico/addAvatarSet.ico"), "&Add AvatarSet", self, triggered=self.addAvatarSet)
self.addAvatarDecorationAct = QAction(QIcon("res/ico/addAvatarDecoration.ico"), "&Add AvatarDecoration", self, triggered=self.addAvatarDecoration)
self.modifyAvatarAct = QAction(QIcon("res/ico/modifyAvatar.ico"), "&Modify Avatar or Decoration", self, triggered=self.modifyAvatar)
self.modifyAvatarSetAct = QAction(QIcon("res/ico/modifyAvatarSet.ico"), "&Modify AvatarSet", self, triggered=self.modifyAvatarSet)
self.settingAct = QAction(QIcon("res/ico/settingPath.ico"), "&路径", self, triggered=self.settingPath)
self.homeAct = QAction(QIcon("res/ico/home.ico"), "&首页", self, triggered=self.homePage)

clip_image003

说明:QAction类提供了一个可以同时出现在菜单和工具条上的抽象用户界面操作。

在图形用户界面应用程序中很多命令可以通过菜单选项、工具条按钮和键盘快捷键调用。因为同一个操作将会被执行,而与它的调用方法无关,并且因为菜单和工具条必须保持同步,所以提供一个操作这样的命令很有用。一个操作可以被添加到菜单和工具条中并且将会自动使它们同步。例如,如果用户按下“加粗”工具条按钮,“加粗”菜单项将会自动被选中。

QAction可以包含图标、菜单文本、快捷键、状态条文本、这是什么文本和工具提示。它们可以分别通过setIconSet()、setText()、setMenuText()、setToolTip()、setStatusTip()、setWhatsThis()和setAccel()来设置。

工具栏

创建工具栏的代码如下:

self.toolbar = self.addToolBar('Home')
self.toolbar.addAction(self.homeAct)
self.toolbar = self.addToolBar('AddAvatar')
self.toolbar.addAction(self.addAvatarAct)
self.toolbar = self.addToolBar('AddAvatarDecoration')
self.toolbar.addAction(self.addAvatarDecorationAct)
self.toolbar = self.addToolBar('AddAvatarSet')
self.toolbar.addAction(self.addAvatarSetAct)
self.toolbar = self.addToolBar('ModifyAvatar')
self.toolbar.addAction(self.modifyAvatarAct)
self.toolbar = self.addToolBar('ModifyAvatarSet')
self.toolbar.addAction(self.modifyAvatarSetAct)

工具栏项也需要关联一个QAction,可以和菜单项共用一个QAction,即一个QAction可以被关联到多个地方。

状态栏

设置状态栏,只需要:

self.statusBar().showMessage("数据加载完成")

第一次调用self.statusBar()获取工具栏时,会初始化工具栏实例,后面再次调用不会在创建新的实例。

程序图标

程序图标分为2个:程序窗口图标;执行文件的图标。

l setWindowIcon(QIcon(“res/ico/icon.ico”))设置程序窗口的图标

l 执行文件的图标,通过打包工具设置

2. UI布局

PyQt的布局系统提供了一个规定子窗口部件布局的简单的和强有力的方式。当你一旦规定了合理的布局,你就会获得如下利益:

l 布置子窗口部件。

l 最高层窗口部件可感知的默认大小。

l 最高层窗口部件可感知的最小大小。

l 调整大小的处理。

l 当内容改变的时候自动更新:

n 字体大小、文本或者子窗口部件的其它内容。

n 隐藏或者显示子窗口部件。

n 移去一些子窗口部件。

PyQt支持的布局方式有很多,如下表所示:

布局相关类

作用

QBoxLayout

Lines up child widgets horizontally or vertically

QButtonGroup

Container to organize groups of button widgets

QFormLayout

Manages forms of input widgets and their associated labels

QGraphicsAnchor

Represents an anchor between two items in a QGraphicsAnchorLayout

QGraphicsAnchorLayout

Layout where one can anchor widgets together in Graphics View

QGridLayout

Lays out widgets in a grid

QGroupBox

Group box frame with a title

QHBoxLayout

Lines up widgets horizontally

QLayout

The base class of geometry managers

QLayoutItem

Abstract item that a QLayout manipulates

QSizePolicy

Layout attribute describing horizontal and vertical resizing policy

QSpacerItem

Blank space in a layout

QStackedLayout

Stack of widgets where only one widget is visible at a time

QStackedWidget

Stack of widgets where only one widget is visible at a time

QVBoxLayout

Lines up widgets vertically

QWidgetItem

Layout item that represents a widget

其中使用比较多的是以下布局方式(或者说是我使用比较多,不代表大家):

  • 水平布局 QHBoxLayout
  • 垂直布局 QVBoxLayout
  • 网格布局 QGridLayout

clip_image005

水平布局

水平布局(QHBoxLayout)顾名思义,将空间水平切成多段,然后通过addWidget、addItem将widget填充指定的位置。如下代码即实现了上图中,适合角色选择的水平布局:

hbox = QHBoxLayout()
self.roleChkBoxGroup.setLayout(hbox)
for _, v in sorted(ParseKeywords.profession.items()):
checkBox = QRadioButton(v["cname"] + " " + str(v["value"]))
hbox.addWidget(checkBox)

删除一个控件,使用removeWidget,或者调用QWidget.hide()一样可以从布局中删除,直到QWidget.show()被调用。下面的垂直布局、网格布局,甚至其他布局都是注意的。

垂直布局

垂直布局(QVBoxLayout)顾名思义,将空间垂直切成多段,然后通过addWidget、addItem将widget填充指定的位置。如下代码即实现了上图中,细节信息的垂直布局(垂直布局中,还嵌套了水平布局):

vbox = QVBoxLayout()
groupBox.setLayout(vbox)

count = QWidget()
hbox = QHBoxLayout()
countLabel = QLabel("细节数目:")
hbox.addWidget(countLabel)
self.countSpineBox = QSpinBox()
self.countSpineBox.setRange(0, 10)
self.countSpineBox.valueChanged.connect(self.countSpineValueChanged)
hbox.addWidget(self.countSpineBox)
hbox.addStretch()
count.setLayout(hbox)
vbox.addWidget(count) #垂直布局,添加widget1

self.detailTable = QTableWidget()
self.detailTable.setColumnCount(9)
self.detailTable.setHorizontalHeaderLabels(
['有效期', '货币类型', '价格', '普通折扣价', '蓝钻价', '蓝钻折扣价', '超级蓝钻折扣价', '赠送礼包ID', '快捷购买'])
vbox.addWidget(self.detailTable) #垂直布局,添加widget2

垂直布局中,还嵌套了水平布局。

说明:QHBoxLayout、QVBoxLayout都是继承自QBoxLayout,为了更好的控制布局,都继承了以下方法:

l QBoxLayout.addSpacing (size)

添加一个不能伸缩的空间(一个QSpacerItem),其宽度设置为size到布局末尾。框布局提供了默认的边距margin和spacing,这是额外添加的空间。

l QBoxLayout.addStretch(stretch)

添加一个可伸缩的空间(一个QSpacerItem),设0为最小值并且伸缩因子为stretch直到布局末尾

网络布局

网格布局(QGridLayout)顾名思义,将空间划分成多行多列的网络,然后通过addWidget、addItem将widget填充到指定的单元格(cell)。这个比较像网页中使用table布局的思路。下面的代码即创建上图中的网格布局:

grid = QGridLayout()
grid.addWidget(setidLabel, 0, 0)
grid.addWidget(self.setidLineEdit, 0, 1)
grid.addWidget(QLabel("(1-2,第2~3-表示适用角色,第4~5-挂点位置,第6~8-序号)"), 0, 2)
grid.addWidget(subidLabel, 1, 0)
grid.addWidget(self.subidLineEdit, 1, 1)
grid.addWidget(QLabel("(套装包含的物品,多个物品适用逗号分隔;必须在套装之前添加)"), 1, 2)
grid.addWidget(fashionLabel, 2, 0)
grid.addWidget(self.fashionLineEdit, 2, 1)
grid.addWidget(nameLabel, 3, 0)
grid.addWidget(self.nameLineEdit, 3, 1)
grid.addWidget(descLabel, 4, 0)
grid.addWidget(self.descLineEdit, 4, 1)
grid.addWidget(marketTagLabel, 5, 0)
grid.addWidget(self.tagCombox, 5, 1)
grid.addWidget(recommendLabel, 6, 0)
grid.addWidget(self.recommendCombox, 6, 1)
grid.addWidget(roleLabel, 8, 0)
grid.addWidget(self.roleChkBoxGroup, 8, 1)
grid.addWidget(beginLabel, 9, 0)
grid.addWidget(self.beginTime, 9, 1)
grid.addWidget(endLabel, 10, 0)
grid.addWidget(self.endTime, 10, 1)

gridWidget = QWidget()
gridWidget.setLayout(grid)

上述往网格中添加的widget都是占一个单元格的情况,其实还支持占用几个单元格。如下代码,往网格中的第二行、第一列添加一个widget,占用1行、2列:

grid.addWidget(self.createDetail(), 1, 0, 1, 2)

网格布局默认是均分每列,为了更好的控制布局,QGridLayout为每列提供了最小宽度(setColumnMinimumWidth())、伸缩因子(setColumnStretch()),为每行提供了最小高度(setRowMinimumHeight())、伸缩因子(setRowStretch())。最小宽/高度很好理解,伸缩因子如下面代码,设置了第二列和三列的比例是1:2。

layout.setColumnStretch(1, 10)
layout.setColumnStretch(2, 20)

3. 二级弹窗

QDialog类是对话框窗口的基类。对话框窗口是主要用于短期任务以及和用户进行简要通讯的顶级窗口。QDialog可以是模态对话框也可以是非模态对话框。QDialog支持扩展性并且可以提供返回值。它们可以有默认按钮。

内置对话框

内置常用的对话框有:QColorDialog、QErrorMessage、QFileDialog、QFontDialog、QInputDialog、QMessageBox、QProgressDialog、QTabDialog、QWizard。

内置的对话框提供了一些常用的功能,使用起来也必将遍历。编写该工具使用到了,选择文件、目录的对话框QFileDialog。

自定义对话框

如果内置的对话框不能满足需求,可以自定义对话框(继承自QDialog)。如下定义了一个设置路径的对话框:

clip_image006

class SettingDialog(QDialog):
def __init__(self, parent=None):
super(SettingDialog, self).__init__(parent)
self.path = Global.path
self.initUI()
self.setWindowIcon(QIcon("res/ico/settingPath.ico"))
self.setWindowTitle("设置")
self.resize(240, 100)

def initUI(self):
grid = QGridLayout()
grid.addWidget(QLabel("路径:"), 0, 0)
self.pathLineEdit = QLineEdit()
self.pathLineEdit.setFixedWidth(200)
self.pathLineEdit.setText(Global.path)
grid.addWidget(self.pathLineEdit, 0, 1)
button = QPushButton("更改")
button.clicked.connect(self.changePath)
grid.addWidget(button, 0, 2)
grid.addWidget(QLabel("<font color='#ff0000'>包含Keywords.xmlAvatar,AvatarSet,Market.xls的路径</font>"), 1, 0, 1, 3)
buttonBox = QDialogButtonBox()
buttonBox.setOrientation(Qt.Horizontal) # 设置为水平方向
buttonBox.setStandardButtons(QDialogButtonBox.Ok|QDialogButtonBox.Cancel)
buttonBox.accepted.connect(self.accept) # 确定
buttonBox.rejected.connect(self.reject) # 取消
grid.addWidget(buttonBox, 2, 1)
self.setLayout(grid)

def changePath(self):
open = QFileDialog()
self.path = open.getExistingDirectory()
self.pathLineEdit.setText(self.path)
print(self.path)

使用对话框,只需要:

dialog = SettingDialog()
if dialog.exec_():
# -----

4. 常用组件

下面介绍编写工具过程中使用到的组件的一些注意事项。

QTableWidget

列自适应

如果有很多列,QTableWidget出出现水平滚动条,但是有不希望有滚动条可以通过设置列自适应方式:

tw.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)

保证所以列都能显示,不会出现水平滚动条,这样有的单元格显示会被截断显示,如图中的"青年套装下装"-->"青年套装...",这时可以设置单元的tooltip提供完整显示的途径。

clip_image008

禁止编辑

编写工具时,有要求QTableWidget展示出来的数据不能编辑,是通过以下方式实现:

tw.setEditTriggers(QAbstractItemView.NoEditTriggers)

QAbstractItemView还定义了其它的模式,如下表所示:

Constant

Value

Description

QAbstractItemView.NoEditTriggers

0

No editing possible.

QAbstractItemView.CurrentChanged

1

Editing start whenever current item changes.

QAbstractItemView.DoubleClicked

2

Editing starts when an item is double clicked.

QAbstractItemView.SelectedClicked

4

Editing starts when clicking on an already selected item.

QAbstractItemView.EditKeyPressed

8

Editing starts when the platform edit key has been pressed over an item.

QAbstractItemView.AnyKeyPressed

16

Editing starts when any key is pressed over an item.

QAbstractItemView.AllEditTriggers

31

Editing starts for all above actions.

按行选择

设置QTableWidget按行选择:

tw.setSelectionBehavior(QAbstractItemView::SelectRows); //整行选中的方式

QAbstractItemView还定义了其它的模式,如下表所示:

Constant

Value

Description

QAbstractItemView.SelectItems

0

Selecting single items.

QAbstractItemView.SelectRows

1

Selecting only rows.

QAbstractItemView.SelectColumns

2

Selecting only columns.

表头排序

如果希望单击QTableWidget表头进行数据排序,可以简单通过以下接口实现:

tw.setSortingEnabled(True)

但是,排序需要注意的2个问题:

l 点了下qtablewidget 的标题,它排序正常,修改数据,在查询,数据显示有问题

重新获取数据之前先关闭可排序性,获取到数据之后再开启排序性

l 排序规则问题,默认使用字母排序

使用以下方式设置单元格,会使用字母排序

item = QTableWidgetItem()
item.setData(Qt.DisplayRole, "xxx")

或者

item = QTableWidgetItem()
item.setText("xxx")

如果需要按照数值排序需要使用以下方式设置单元格

item = QTableWidgetItem()
item.setData(Qt.DisplayRole, int(1212))

自定义单元格控件

可以对QTableWidget自定义(添加)widget,如下为QTableWidget设置单元格为一个下拉选择的QCombox

combox = QComboBox()
for _, v in ParseKeyword.currencyType.items():
combox.addItem(v["cname"], v["value"])
combox.setCurrentText("点券")
tw.setCellWidget(row, 1, combox)

效果如下图所示:

clip_image009

QDateTimeEdit

显示格式

默认的时间显示格式(如2015/1/16 17:42),可能不满足需求,可以通过setDisplayFormat()设置显示格式来定制。格式选项如下所示:

这些是可能用到的日期表达式:

l d - 没有前置0的数字的天(1-31)

l dd - 前置0的数字的天(01-31)

l ddd - 缩写的日名称(Mon-Sun)。使用QDate.shortDayName()。

l dddd - 长的日名称(Monday-Sunday)。使用QDate.longDayName()。

l M - 没有前置0的数字的月(1-12)

l MM - 前置0的数字的月(01-12)

l MMM - 缩写的月名称(Jan-Dec)。使用QDate.shortMonthName()。

l MMMM - 长的月名称(January-December)。使用QDate.longMonthName()。

l yy - 两位数字的年(00-99)

l yyyy - 四位数字的年(0000-9999)

这些是可能用到的时间表达式:

l h - 没有前置0的数字的小时(0-23或者如果显示AM/PM时,1-12

l hh - 前置0的数字的小时(00-23或者如果显示AM/PM时,01-12

l m - 没有前置0的数字的分钟(0-59

l mm - 前置0的数字的分钟(00-59

l s - 没有前置0的数字的秒(0-59

l ss - 前置0的数字的秒(00-59

l z - 没有前置0的数字的毫秒(0-999

l zzz - 前置0的数字的毫秒(000-999

l AP - 切换为AM/PM显示。AP将被“AM”或“PM”替换。

l ap - 切换为am/pm显示。ap将被“am”或“pm”替换。

如工具中使用的格式为:

setDisplayFormat("yyyy-MM-dd hh:mm:ss")

显示效果如下图所示:

clip_image010

弹出日期选择窗口

希望点击QDateTimeEdit可以弹出日期选择窗口,可以简单的通过setCalendarPopup(True)实现,非常的简单。

5. 打包

python常用的打包工具有py2exe、pyinstaller、cx_freeze,而且现在都开始支持python3,py2exe可以打包成单exe文件,一般简单的东西都是用它来打包供其他人使用。但是使用py2exe打包PyQt5时,碰到了不少错误,后面干脆使用cx_freeze打包一次成功(不足之处,就是不能打包成单个exe)。下面简单介绍编写setup.py几个关键的点,详细的参考官方文档(http://cx-freeze.readthedocs.org/en/latest/index.html)。

l 默认只会打包代码文件,如果程序有非代码文件,如配置、资源文件需要打包,需要显示指定。如"include_files": ["setting.ini", "res"],打包时会将setting.ini文件、res资源目录拷贝到exe目录下。

l cx_freeze会自动检测依赖文件,但是有时候会抽风,可以通过"packages": ["os", "xlrd3", "xlwt3", "lxml"]显示包含。同时对不要的包,可以"excludes": ["tkinter"]指定不要编译到最终的软件包中。

l 指定文件名需要带exe后缀,cx_freeze是不会自动添加exe后缀的。

l 如果需要一次编译多个exe,可以在executables数组中列出多个,例如:

executables = [
Executable("main.py", base=base, targetName="Joker3DAvatarMgr.exe", compress=True, icon="res/ico/icon.ico"),

Executable("test.py", base=base, targetName="test.exe", compress=True, icon="res/ico/test.ico")
]

完整的setup.py文件如下所示:

import sys
from cx_Freeze import setup, Executable

# GUI applications require a different base on Windows (the default is for a
# console application).
base = None
if sys.platform == "win32":
base = "Win32GUI"

# Dependencies are automatically detected, but it might need fine tuning.
build_exe_options = {
"packages": ["os", "xlrd3", "xlwt3", "lxml"],
"excludes": ["tkinter"],
"include_files": ["setting.ini", "res"]
}

#
executables = [
Executable("main.py", base=base, targetName="Joker3DAvatarMgr.exe", compress=True, icon="res/ico/icon.ico")
]

setup( name = "setup",
version = "0.1",
description = "Joker3D prop manager tool!",
author = "tylerzhu",
author_email = "
saylor.zhu@gmail.com",
options = {"build_exe": build_exe_options},
executables = executables,
)

编写好setup.py之后,可以通过python setup.py build打包。

网上有不少人反馈打包之后,放到没有按照PyQt的PC上执行,会报以下错误:“This application failed to start because it could not find or load the Qt platform plugin windows”

clip_image011

这个问题,我以前也碰到过,但是这次我用的Python3.4 + cx_freeze 4.3.4 + PyQt5-5.4-gpl-Py3.4-Qt5.4.0-x32.exe并没有出现这个问题。如果出现了这个问题也不要紧,通过以下方法可以解决:将PyQt5安装目录(Lib\site-packages\PyQt5)下的libGLESv2.dll拷到打包的exe目录下即可。




本文转自吴秦博客园博客,原文链接:http://www.cnblogs.com/skynet/p/4229556.html,如需转载请自行联系原作者

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/279157.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

plex实现流媒体服务器_Plex继续远离服务器,提供网络节目

plex实现流媒体服务器() Plex now offers a “Web Shows” feature in certain versions of their interface, providing access to shows from brands like TWiT, GQ, and Popular Science. Plex现在在其界面的某些版本中提供了“网络节目”功能&#xff0c;可以访问TWiT&…

MIME协议(三) -- MIME邮件的组织结构

一封MIME邮件可以由多个不同类型的MIME消息组合而成&#xff0c;一个MIME消息表示邮件中的一个基本MIME资源或若干基本MIME消息的组合体。每个MIME消息的数据格式与RFC822数据格式相似&#xff0c;也包括头和体两部分&#xff0c;分别称为MIME消息头和MIME消息体&#xff0c;它…

discord linux_最好的Discord机器人来启动服务器

discord linuxDiscord has an extensive API and good support for bots on their platform. Because of this, there are tons of bots to go around. However, many of them just copy one another’s functionality. We’ve picked out the ones that do it right, and comp…

java获取前端json数据_java如何获取前端ajax传来的json对象

假设使用 jQuery 中的 ajax1. Json 对象前端代码示例$.ajax({url : http://localhost:8888/demo,type: post,data: {userName:15488779956}success: function(data) {// TODO}})后台代码示例RestControllerpublic class Demo {/*** 方法 1 使用 HttpServletRequest 接收* */Req…

版本控制介绍以及常用的版本控制工具

版本控制是指对软件开发过程中各种程序代码、配置文件及说明文档等文件变更的管理&#xff0c;是软件配置管理的核心思想之一。 编写一个成熟可用的程序是一个工作量很大的工程&#xff0c;并非我们一次性就可以搞定的工作&#xff0c;所以在开发过程当中需要&#xff1a; 1、 …

2019年4月第四周_2012年4月最佳怪胎文章

2019年4月第四周This past month we covered topics such as how to use a 64-bit web browser on Windows, the best tips and tweaks for getting the most out of Firefox, how to check out library books on your Kindle for free, and more. Join us as we look back at …

matlab循环遍历数组_Matlab - 访问for循环中最大值的索引,并使用它从数组中删除值...

我想递归地找到一系列矩阵中的最大值(第8列&#xff0c;具体)&#xff0c;然后使用该最大值的索引来设置数组中的所有值&#xff0c;索引最大为NaN的最大索引(对于列14:16) . 很容易找到最大值和索引&#xff0c;但是使用for循环为多个数组做这件事我很难过 .如果没有for循环&a…

【资料整理】编译安装nginx

【nginx】编译安装nginx 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311…

游荡的奶牛

沙雕题目 读错题了&#xff0c;不想多说 转载于:https://www.cnblogs.com/bullshit/p/9811058.html

物体成瘾性_科技成瘾使我们不那么快乐。 那是一个市场机会。

物体成瘾性Compulsively checking social networks makes us less happy. I think we all understand this intuitively, the same way we understand that working out more and eating better is a good idea. 强迫检查社交网络使我们不那么开心。 我认为我们所有人都可以凭直…

mysql 不要统计null_浅谈为什么Mysql数据库尽量避免NULL

在Mysql中很多表都包含可为NULL(空值)的列&#xff0c;即使应用程序并不需要保存NULL也是如此&#xff0c;这是因为可为NULL是列的默认属性。但我们常在一些Mysql性能优化的书或者一些博客中看到观点&#xff1a;在数据列中&#xff0c;尽量不要用NULL 值&#xff0c;使用0&…

Swing学习1——总体概述

以下来自于JDK1.6 一、Swing学习我划分为两个方面&#xff1a; 一方面Swing的界面设计部分&#xff0c;包括相关组件类的继承关系&#xff0c;组件的功能用途&#xff0c;布局管理&#xff1b; 1.首先继承关系上自上而下为 java.lang.Object java.awt.Component java.awt.Conta…

装饰设计模式和例题

文件复制程序&#xff1a; 将一个文件复制一份出来&#xff0c;实现方法很简单&#xff0c;使用FileInputStream读取文件内容&#xff0c;然后使用FileOutputStream写入另一个文件&#xff0c;利用read方法的返回值作为while循环的条件&#xff0c;进行一边读一边写。 代码示例…

mysql操作手册我_MySQL使用指南一

我将MySQL常用指令整理出来分享给大家。1. 列出所有数据库mysql> show databases;2. 创建数据库mysql> create databases MyStorage;3. 打开数据库mysql> use MyStorage;4. 创建表mysql> create table Storage-> (-> id int,-> name varchar(50),-> pr…

谷歌地图将很快显示电动汽车充电站

If you’re out on the road in the future and find your electric vehicle is in dire need of a charge, you’ll soon be able to look to Google Maps for help finding a charging station. 如果您将来出门在外&#xff0c;并且发现您的电动汽车急需充电&#xff0c;那么…

JS4

1. js的本质就是处理数据。数据来自于后台的数据库。 所以变量就起到一个临时存储数据的作用。 ECMAScript制定了js的数据类型。 数据类型有哪些&#xff1f; 字符串 String数字 Number布尔 BooleanNull 空Undefined Object 对象Array 数组 json function …

ovirt官方安装文档 第三章

第3章&#xff1a;安装oVirt 安装oVirt引擎包 在您可以配置和使用oVirt引擎之前&#xff0c;您必须安装 rhevm 包和依赖关系。 安装oVirt引擎包 在开始安装oVirt之前&#xff0c;添加官方仓库&#xff1a; # yum install http://resources.ovirt.org/pub/yum-repo/ovirt-releas…

mysql获取查询策略语句_MySQL数据库查询性能优化策略

优化查询使用Explain语句分析查询语句Explain 用来分析 SELECT 查询语句&#xff0c;开发人员可以通过分析 Explain 结果来优化查询语句。通过对查询语句的分析,可以了解查询语句的执行情况,找出查询语句执行的瓶颈,从而优化查询语句.使用索引查询MySql中提高性能的一个最有效的…

松弛变量可以为负吗_如何为松弛安装(非官方)暗模式

松弛变量可以为负吗Slack still doesn’t have a dark mode. They have dark themes, but those only let you customize the sidebar colors, leaving the main window white. With the release of system-wide dark modes on macOS Mojave and Windows 10, Slack feels very …

如何使用系统自带的日志转储功能logroate.存放应用日志

Linux日志服务介绍 &#xff11;. 在Linux系统&#xff0c;大部分日志都是由syslog日志服务驱动和管理的 syslog服务由两个重要的配置文件控制管理&#xff0c;分别是/etc/syslog.conf主配置文件和/etc/sysconfig/syslog辅助 配置文件&#xff0c; /etc/init.d/syslog是启动脚本…