??xml version="1.0" encoding="utf-8" standalone="yes"?> 基本知识Q?
游戏规则很简单,是利用加减乘除扑克牌的Q一4张牌的组合,q算后得到结?4.
界面用Qt完成?
界面没有多下功夫Q可以添加时间提醒,修改目标数|24Q,增加牌数应该也是可以的,不过我没有去试一下。感觉花哨了没有单来的好一些?
next?x)生成新的牌。answer查看{案?
牌的数g用QlineEdit做的Q可以自p|倹{?
CardCalculationcM(x)Ҏ(gu)输入的牌?vector<double>)计算出响应的表达式?
计算程Q?
数据l构的书q没看完Q算法完全是自己凭空去试。最后写出来后其实也不知道自己再考虑q方侉K题时思\怎么展开。尽快抽旉看下法的书才行?
我们?#8251;作ؓ(f)L的操作符Q?-*/Q来说明?
Ҏ(gu)vec元素个数:
1. a※bQ直接计即可?
2. a※b※c,可能操作?
(a※b)※c
a※(b※c)
3. a※b※c ※d,可能操作为:(x)
(a※b)※c ※d
a※(b※c) ※d
a※b※(c ※d)
因此采用递归求解Q好处是如果增加牌的张数时应该容易修改一些,具体实现函数为calCards?
刚传qvecӞ大小?Q属于第三种情况。遍历vecQ将可能操作后Ş成的新的vector再次作ؓ(f)函数参数传入Q直到遇?情况q回Q如果满回trueQ否则返回false。返回trueӞ修改W二个参C存表辑ּ?
关于如何q回表达式这里我弄了很长旉。计出正确的表辑ּ后,每次递归都会(x)加一Ҏ(gu)P其实后面应该可以对表辑ּ优化下可能减括L(fng)数量Q不q我没有写?
E序里都写了注释~如果q是有问题请l我留言J /Files/izualzhy/TwentyFourGame.rar
]]>
原文链接:Qtl典出错信息之undefined reference to `vtable for classname
q个出错信息太常见了Q用qQt两个月以上的朋友基本上都能自p决了Q因为太l典了,可以l新手参考?
出错信息一般类?undefined reference to `vtable for classname MyWidget`
在执行make命o(h)后出现?
出错原因是在定义cȝ时候ؓ(f)了能使用signals和slot,在类定义的后面加了Q_OBJECT引v?因ؓ(f)Q_OBJECT是一个宏Q在不同的类中展开是不同的代码Q例如在mywidgeth.h中生成的
public:
template inline void qt_check_for_QOBJECT_macro(const T &_q_argument) const {
int i = qYouForgotTheQ_OBJECT_Macro(this, &_q_argument); i = i;
}
static const QMetaObject staticMetaObject;
virtual const QMetaObject *metaObject() const;
virtual void *qt_metacast(const char *);
static inline QString tr(const char *s, const char *c = 0) {
return staticMetaObject.tr(s, c);
}
static inline QString trUtf8(const char *s, const char *c = 0)
{
return staticMetaObject.trUtf8(s, c);
}
static inline QString tr(const char *s, const char *c, int n) {
return staticMetaObject.tr(s, c, n);
}
static inline QString trUtf8(const char *s, const char *c, int n) {
return staticMetaObject.trUtf8(s, c, n);
}
virtual int qt_metacall(QMetaObject::Call, int, void **); private:
可以看到以上的代码声明了3个从父类l承?个虚函数。本来这三个函数的实现应该是由moc_mywidget.cpp来完成?br/>而当前的错误正是因ؓ(f)Makefile里没有将moc_mywidget.cpp加入~译引v?
Makefile背后的原因是qmakeQ因为Qt的编译系l是通过qmake?pro文g转换成Makefile文g。当qmake扫描.h代码时发现有Q_OBJECTq样字眼的代码时Q会(x)一个用moc生成moc_xxx.cpp代码的依赖关pd到Makefile里。如果扫描时没有扑ֈQ_OBJECT׃?x)生成额外的moc_xxx.cppq样的文件?
出现最初一q的原因是在执行qmake的时?h代码里ƈ没有O_OBJECTq样的代码。而执行make的时?h里已l有Q_OBJECT了,解决的方法就是重新执行qmakeQ然后执行make.
—?
shirokiQ另外我再加一句, q有一U可能性是写代码的人把所有的代码都写在了.cpp文g中。要知道moc工具只读.h文gQ如果把Q_OBJECT宏放在cpp里moc是看不到的……所以大家写代码q是要遵守声明放.h实现放cpp的规矩比较好?
E序q行效果?br />
负责处理xml文g的是XbelWriterQXbelReaderQ界面的实现是由MainWindow完成?/p>
保存后的xbel文g前几行是q样?br /><?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xbel>
<xbel version="1.0">
<folder folded="yes">
<title>Literate Programming</title>
<bookmark href=" <title>Synopsis of Literate Programming</title>
</bookmark>
如果不断用readNextQ)Q即以下几行代码d文g的话
while (!xml.atEnd()) {
qDebug() << "name " << xml.name() << "tokentype " << xml.tokenType();
if (xml.isCharacters()) {
qDebug() << xml.text();
}
xml.readNext();
}
前几行输出:(x)
name "" tokentype 0
name "" tokentype 2
name "" tokentype 8
name "xbel" tokentype 4
name "" tokentype 6
"
"
name "folder" tokentype 4
name "" tokentype 6
"
"
name "title" tokentype 4
name "" tokentype 6
"Literate Programming"
name "title" tokentype 5
name "" tokentype 6
"
"
name "bookmark" tokentype 4
name "" tokentype 6
"
"
name "title" tokentype 4
name "" tokentype 6
"Synopsis of Literate Programming"
name "title" tokentype 5
l合源代码里关于Tokentype的enum定义Q?br />enum TokenType {
NoToken = 0,
Invalid,
StartDocument,
EndDocument,
StartElement,
EndElement,
Characters,
Comment,
DTD,
EntityReference,
ProcessingInstruction
};
可以看出Q?br />1.readNext是一个一个的来读Q碰?lt;xxx>,</xxx>,以及...>xxx<...的文?br /> 理一下读取的程Q?br /> 1.没有dM东西QNoToken
2.d<?xml version="1.0" encoding="UTF-8"?>QStartDocument
3.d<!DOCTYPE xbel>QDTD
4.d<xbel version="1.0">QStartElement
5.d<xbel version="1.0">?lt;folder folded="yes">之间的charactersQ如果打印相应的unicode出来的话Q是10 32 32 32 32
?个换?4个空|直接打印是
"
"
q个了,可见...>xxx<...的文字都?x)读取,即是换?I格之类?br /> 6.d<folder folded="yes">QStartElement
。。。。。?br />2.
遇到q种<separator/>则类g<separator></separator>
name "separator" type 4
name "separator" type 5
利用void QXmlStreamWriter::writeEmptyElement("separator")可以写入成这?/p>
1.XbelWriter Class
写入的过E其实是很简单的Q具体看代码Q?br /> bool XbelWriter::writeFile(QIODevice *device)
{
xml.setDevice(device);
xml.writeStartDocument();//生成L1
xml.writeDTD("<!DOCTYPE xbel>");//生成L2
xml.writeStartElement("xbel");//与下一行共同生成L3
xml.writeAttribute("version", "1.0");
for (int i = 0; i < treeWidget->topLevelItemCount(); ++i)
writeItem(treeWidget->topLevelItem(i));
xml.writeEndDocument();
return true;
}
2.XbelReader Class
首先d到合适的Element
bool XbelReader::read(QIODevice *device)
{
xml.setDevice(device);
if (xml.readNextStartElement()) {
if (xml.name() == "xbel" && xml.attributes().value("version") == "1.0")//卌到name为xbelQ属性version?.0的Element?br />//The actual process of reading only takes place if the file is a valid XBEL 1.0 file.
readXBEL();
else
xml.raiseError(QObject::tr("The file is not an XBEL version 1.0 file."));
}
return !xml.error();
}
由注释可以看到工作函数是readXBEL(),整个程p几行代码完成Q里面函数用到递归Q?br />void XbelReader::readXBEL()
{
Q_ASSERT(xml.isStartElement() && xml.name() == "xbel");
while (xml.readNextStartElement()) {
if (xml.name() == "folder")
readFolder(0);
else if (xml.name() == "bookmark")
readBookmark(0);
else if (xml.name() == "separator")
readSeparator(0);
else
xml.skipCurrentElement();
}
}
看下skipCurrentElement()的源代码Q?br />void QXmlStreamReader::skipCurrentElement()
{
int depth = 1;
while (depth && readNext() != Invalid) {
if (isEndElement())
--depth;
else if (isStartElement())
++depth;
}
}Q可以看到变量depth在进入一个新的element?1Q出来则-1
因此直到现在的这个elementl束Q遇到相应的</xxx>Q,函数才结束退?br />Qt Assistant里的注释Q?br />The readXBEL() function reads the name of a startElement and calls the appropriate function to read it, depending on whether if its a "folder", "bookmark" or "separator". Otherwise, it calls skipCurrentElement().
卛_果Element的name为folder,bookmark,separatorӞd内容Q否则skip
具体?x)遇到的有这么几U:(x)
<folder folded="yes">
<title>Literate Programming</title>
<bookmark href="<separator/>
需要不同的函数来处?br />例子里分别用?br />readTitle(),readSeparator(),readFolder(),readBookmark()
我主要学?fn)了下readFolder()
fold有两U情?br /><folder folded="yes">
<folder folded="no">
d时差别的处理代码
QTreeWidgetItem *folder = createChildItem(item);
bool folded = (xml.attributes().value("folded") != "no");
treeWidget->setItemExpanded(folder, !folded);
W三行注释掉后对比下囄
可见默认是不expand?br />Sets the item referred to by item to either closed or opened, depending on the value of expand.
This function is deprecated. Use QTreeWidgetItem::setExpanded() instead.
void QTreeWidgetItem::setExpanded ( bool expand )
Expands the item if expand is true, otherwise collapses the item
主要是展开q是摺叠V?br />folder下面的element可能name为titleQbookmarkQseparatorQ还可能再由folderQ像Useful C++ Links下面q有STL Qt{,需要递归处理Q因此还需要以下代?br /> while (xml.readNextStartElement()) {
if (xml.name() == "title")
readTitle(folder);
else if (xml.name() == "folder")
readFolder(folder);
else if (xml.name() == "bookmark")
readBookmark(folder);
else if (xml.name() == "separator")
readSeparator(folder);
else
xml.skipCurrentElement();
}
只不q跟readXBEL里参C?/p>
再看下while-loop condition
bool QXmlStreamReader::readNextStartElement ()
Reads until the next start element within the current element. Returns true when a start element was reached. When the end element was reached, or when an error occurred, false is returned.
The current element is the element matching the most recently parsed start element of which a matching end element has not yet been reached. When the parser has reached the end element, the current element becomes the parent element.
This is a convenience function for when you're only concerned with parsing XML elements.
看下该函数源代码Q?br />bool QXmlStreamReader::readNextStartElement()
{
while (readNext() != Invalid) {
if (isEndElement())
return false;
else if (isStartElement())
return true;
}
return false;
}
可以看到是读取下一个记P如果是endElementQ则q回falseQ否则true
再对比下xml文g看下该函数是如何用来在这个大的element内部遍历?br /><folder folded="yes">
<title>Literate Programming</title>
<bookmark href=" <title>Synopsis of Literate Programming</title>
</bookmark>
<bookmark href=" <title>Literate Programming: Propaganda and Tools</title>
</bookmark>
1.d记号?lt;title>Q进入readTitle()
2.d内容Q记L(fng)动到</title>
3.q入while条gQ即readNextStartElement()Q此时虽然TokenType是EndElementQ但是readNext后,变ؓ(f)startElementQ即bookmarkQ进入readBookmark()
4.同folderQbookmark也一直要d</bookmark>
再看?br />QTreeWidgetItem *XbelReader::createChildItem(QTreeWidgetItem *item)
{
QTreeWidgetItem *childItem;
if (item) {
childItem = new QTreeWidgetItem(item);
} else {
childItem = new QTreeWidgetItem(treeWidget);
}
childItem->setData(0, Qt::UserRole, xml.name().toString());
return childItem;
}
setData参数可以指定不同的role
Qt::UserRole 32 The first role that can be used for application-specific purposes.
通过相应的data函数可以取出该QString
通过l?br />QTreeWidgetItem的构造函C入不同的参数Q可以传入QTreeWidgetQ也可以是QTreeWidgetItem
QTreeWidget?x)根据各个item的关p而排列好~进Q关于QTreeWidgetq没用过Q有I学习(fn)一下?br />
跟用QXmlStreamReader QXmlStreamWriter是一L(fng)Q区别在于处理的q程?br />前一个例子主要是传参的方式,QTreeWidget传给xmlReaderQxmlWriter
dxml到QTreeWidget里,随着dditem到里面,写的时候则遍历q个QTreeWidgetQ把item写入到xml文g
q个例子则是由QTreeWidgetz一个XbelTree的类出来Q私有成员里有一个QDomDocument的对象?br />是两种处理方式吧,但传参和l合的方式每个例子都是可以用的,可能只是QXmlStream和QDom更适合哪种方式里了?br />q个例子主要是学?fn)QDom Classes
先脓(chung)一个Qt Assistant里的一D代?br />The QDom classes are typically used as follows:
QDomDocument doc("mydocument");
QFile file("mydocument.xml");
if (!file.open(QIODevice::ReadOnly))
return;
if (!doc.setContent(&file)) {
file.close();
return;
}
file.close();
// print out the element names of all elements that are direct children
// of the outermost element.
QDomElement docElem = doc.documentElement();
QDomNode n = docElem.firstChild();
while(!n.isNull()) {
QDomElement e = n.toElement(); // try to convert the node to an element.
if(!e.isNull()) {
cout << qPrintable(e.tagName()) << endl; // the node really is an element.
}
n = n.nextSibling();
}
// Here we append a new element to the end of the document
QDomElement elem = doc.createElement("img");
elem.setAttribute("src", "myimage.png");
docElem.appendChild(elem);
Once doc and elem go out of scope, the whole internal tree representing the XML document is deleted.
To create a document using DOM use code like this:
QDomDocument doc("MyML");
QDomElement root = doc.createElement("MyML");
doc.appendChild(root);
QDomElement tag = doc.createElement("Greeting");
root.appendChild(tag);
QDomText t = doc.createTextNode("Hello World");
tag.appendChild(t);
QString xml = doc.toString();
加上q几句话产生xml文g查看内容
QFile file("mydocument.xml");
file.open(QIODevice::ReadWrite);
QTextStream m_out(&file);
doc.save(m_out,4);
file.close();
产生的document内容Q?br /><!DOCTYPE MyML>
<MyML>
<Greeting>Hello Wolrd!</Greeting>
</MyML>
1.
XbelTreel承自QTreeWidget
每一列的大小是否可以自由改变Q由该函数决?br />void QHeaderView::setResizeMode ( ResizeMode mode )
Sets the constraints on how the header can be resized to those described by the given mode.
The resize mode specifies the behavior of the header sections. It can be set on the entire header view or on individual sections using setResizeMode().
Constant Value Description
QHeaderView::Interactive 0 The user can resize the section. The section can also be resized programmatically using resizeSection(). The section size defaults to defaultSectionSize. (See also cascadingSectionResizes.)
QHeaderView::Fixed 2 The user cannot resize the section. The section can only be resized programmatically using resizeSection(). The section size defaults to defaultSectionSize.
QHeaderView::Stretch 1 QHeaderView will automatically resize the section to fill the available space. The size cannot be changed by the user or programmatically.
QHeaderView::ResizeToContents 3 QHeaderView will automatically resize the section to its optimal size based on the contents of the entire column or row. The size cannot be changed by the user or programmatically. (This value was introduced in 4.2)
最上一排的headview的指针通过该函数获?br />QHeaderView * QTreeView::header () const
Returns the header for the tree view.
2.
<img src="myimg.png">
tagName:img
name:src
value:"myimg.png"
QDom
A
QDomElement QDomDocument::documentElement () const
Returns the root element of the document.
该函数返回的卛_DOCTYPE后最大的一个ElementQ即root
B
QDomElement QDomNode::firstChildElement ( const QString & tagName = QString() ) const
Returns the first child element with tag name tagName if tagName is non-empty; otherwise returns the first child element. Returns a null element if no such child exists.
该函数返回指定tagName的QDomElement
相关的有
firstChildElement(),lastChildElement(), previousSiblingElement(), and nextSiblingElement().
都需要指定tagName
当子l点的不是一个ElementӞ使用函数获得W一个子节点
QDomNode QDomNode::firstChild () const
Returns the first child of the node. If there is no child node, a null node is returned. Changing the returned node will also change the node in the document tree.
获得最后一个子l点
QDomNode QDomNode::lastChild () const
Returns the last child of the node. If there is no child node, a null node is returned. Changing the returned node will also change the node in the document tree.
See also firstChild() and childNodes().
获得下一个子节点
QDomNode QDomNode::nextSibling () const
Returns the next sibling in the document tree. Changing the returned node will also change the node in the document tree.
If you have XML like this:
<h1>Heading</h1>
<p>The text...</p>
<h2>Next heading</h2>
and this QDomNode represents the <p> tag, nextSibling() will return the node representing the <h2> tag.
获得上一个子节点
QDomNode QDomNode::previousSibling () const
Returns the previous sibling in the document tree. Changing the returned node will also change the node in the document tree.
For example, if you have XML like this:
<h1>Heading</h1>
<p>The text...</p>
<h2>Next heading</h2>
and this QDomNode represents the <p> tag, previousSibling() will return the node representing the <h1> tag.
你也可以直接获得l点的列?br />QDomNodeList QDomNode::childNodes () const
Returns a list of all direct child nodes.
Most often you will call this function on a QDomElement object.
For example, if the XML document looks like this:
<body>
<h1>Heading</h1>
<p>Hello <b>you</b></p>
</body>
Then the list of child nodes for the "body"-element will contain the node created by the <h1> tag and the node created by the <p> tag.
The nodes in the list are not copied; so changing the nodes in the list will also change the children of this node.
DOM是一U解析由万维|协?W3C)所开发的XML文档的标准应用程序编E接口。Qt提供一套用于读取、操作和~写XML文档的非验证型二UDOM实现?/p>
DOM把XML文g表示成内存中的一|(wi)。我们可以按需要遍历这个DOM?wi),也可以修改这个?wi)q把它作为XML文g保存到磁盘中?/p>
让我们考虑如下q个XML文档Q?/p>
<doc>
<quote>Scio me nihil scire</quote>
<translation>I know that I know nothing></translation>
</doc>
它对于如下所C的DOM?wi)?x)
Document
Element(doc)
Element(quote)
Text(“Scio me nihil scire”)
Element(translation)
Text(“I know that I know nothing”)
q个DOM?wi)包含不同类型的节点。例如,Element节点对应打开标签以及与它匚w的关闭标{?font color="#0000ff">在这两个标签之间的内容则作ؓ(f)q个Element节点的子节点出现?/font>Q注意蓝色字体)
上面的介l主要是用来说明dom?wi)的l构情况Q下面则q入正题看如何通过qt来达C改xml文g的目的。本文中主要说明如何修改xml属性g及节点|
修改属性值的代码如下Q?/font>
bool QXmlEdit::SetAValue(const QString &key, const QVariant &value) { try { QString tag; QString attName; QStringList sl=key.split("/"); tag = sl.at(0); attName = sl.at(1); QDomElement docElem = doc.documentElement(); QDomNodeList nodeList = docElem.elementsByTagName(tag); if (nodeList.count() >0 ) { QDomElement el = nodeList.at(0).toElement(); el.setAttribute(attName,value.toString()); //讄属性?/span>QFile file(fileName); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { return false; } QTextStream out(&file); doc.save(out,4); } return true; } catch (...) { return false; } }修改节点值的代码如下Q?/font>bool QXmlEdit::SetTValue(const QString &key, const QVariant &value) { try { QDomElement docElem = doc.documentElement(); QDomNodeList nodeList = docElem.elementsByTagName(key); if (nodeList.count() >0 ) { QDomElement el = nodeList.at(0).toElement(); //tag为key的节? QDomNode oldnode = el.firstChild(); //标签之间的内容作点的子节点出玎ͼ得到原来的子节点 el.firstChild().setNodeValue(value.toString()); //用提供的value值来讄子节点的内容QDomNode newnode = el.firstChild(); //g改过后的子节?/span>el.replaceChild(newnode,oldnode); //调用节点的replaceChildҎ(gu)实现修改功能 QFile file(fileName); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { return false; } QTextStream out(&file); doc.save(out,4); } return true; } catch (...) { return false; } }
x我们实C修改xml属性及text的功能?/p>
Ok Cancel Button可以直接使用Q再看下acceptedQrejected信号在什么情况下发?br />void QDialogButtonBox::accepted () [signal]
This signal is emitted when a button inside the button box is clicked, as long as it was defined with the AcceptRole or YesRole.
void QDialogButtonBox::rejected () [signal]
This signal is emitted when a button inside the button box is clicked, as long as it was defined with the RejectRole or NoRole.
Q而Ok cancel Button的定义:(x)
QDialogButtonBox::Ok 0x00000400 An "OK" button defined with the AcceptRole.
。。?
QDialogButtonBox::Cancel 0x00400000 A "Cancel" button defined with the RejectRole.
此外q有很多ButtonQ如Save Apply{,都定义在
enum QDialogButtonBox::StandardButton
flags QDialogButtonBox::StandardButtons里了?br />用v来是不是很方便呢Q?br />不过该类q有很多东西没看懂,如ActionRole{,感觉有空q个cd以单独学?fn)一下?br />B
Incomplete Form Widget是一个QMEssgeBOxQ:(x)warning
之所以两个类归结Z个知识点Q是因ؓ(f)QMessageBox与上面的cL一点还是很像的Q那是Button不用定义。。?br />QMessageBox的Button都定义在q里?br />enum QMessageBox::StandardButton
flags QMessageBox::StandardButtons
跟上面的很像
用v来也非常方便Q看下Incomplete Form Widget的相关代?br />QMessageBox::StandardButton answer;
answer = QMessageBox::warning(this, tr("Incomplete Form"),
tr("The form does not contain all the necessary information.\n"
"Do you want to discard it?"),
QMessageBox::Yes | QMessageBox::No);
if (answer == QMessageBox::Yes)
reject();
关于warning的定?br />Static Public Members
。。?br />StandardButton warning ( QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton )
注意是Static?br />q回cd即ؓ(f)上面说的枚Dcd
2.
QTableView的上边和左边1 2/1 2 3 4的窗口也可以q一步操?br />通过
QHeaderView * horizontalHeader () const
拿到对应指针Q例?br />itemsTable->verticalHeader()->hide();可以将左边? 2 3 4隐藏?br />3.
QAction * QMenu::addAction ( const QString & text )
This convenience function creates a new action with text. The function adds the newly created action to the menu's list of actions, and returns it.
q个函数非常好用Q因为可以自动创Z个actionQ返回值就是这个action的指针,同时另外几个重蝲函数有的更加方便
QAction * QMenu::addAction ( const QString & text, const QObject * receiver, const char * member, const QKeySequence & shortcut = 0 )
This is an overloaded function.
This convenience function creates a new action with the text text and an optional shortcut shortcut. The action's triggered() signal is connected to the receiver's member slot. The function adds the newly created action to the menu's list of actions and returns it.
在创建的时候,可以直接指定q接到的槽?br />例子里这里分别用CQ?br />QAction *newAction = fileMenu->addAction(tr("&New..."));
newAction->setShortcuts(QKeySequence::New);
printAction = fileMenu->addAction(tr("&Print..."), this, SLOT(printFile()));
printAction->setShortcuts(QKeySequence::Print);
printAction->setEnabled(false);
4.
Order Form Widget里主H口是QTabWidget
其下昄H口是一个QTextEditQ通过利用QTextCursor QTextFrame{做的非常好?br />因ؓ(f)q个排版之前完全不知道怎么MQ代码涉及了很多的类Q都很简单的接口Q,所以跟着代码做了一遍注释学?fn)了?br /> QTextCursor cursor(editor->textCursor());
cursor.movePosition(QTextCursor::Start);//取得指针q放在最开始的位置
QTextFrame *topFrame = cursor.currentFrame();//Note that topFrame is the editor's top-level frame and is not shown in the document structure.
QTextFrameFormat topFrameFormat = topFrame->frameFormat();
topFrameFormat.setPadding(16);//讄内容的边距,L后对比下
topFrame->setFrameFormat(topFrameFormat);
QTextCharFormat textFormat;
QTextCharFormat boldFormat;
boldFormat.setFontWeight(QFont::Bold);//讄字体Q一?x)?x)用到
QTextFrameFormat referenceFrameFormat;
referenceFrameFormat.setBorder(1);
referenceFrameFormat.setPadding(8);
referenceFrameFormat.setPosition(QTextFrameFormat::FloatRight);//该句使得昄位置从右边开始,Ҏ(gu)Left后对比下
referenceFrameFormat.setWidth(QTextLength(QTextLength::PercentageLength, 40));//QTextLength有三U类型,含义如下
Constant Value Description
QTextLength::VariableLength 0 The width of the object is variable
QTextLength::FixedLength 1 The width of the object is fixed
QTextLength::PercentageLength 2 The width of the object is in percentage of the maximum width
cursor.insertFrame(referenceFrameFormat);//关于该句的介l?br /> QTextFrame * QTextCursor::insertFrame ( const QTextFrameFormat & format )
Inserts a frame with the given format at the current cursor position(), moves the cursor position() inside the frame, and returns the frame.
If the cursor holds a selection, the whole selection is moved inside the frame.
注意l的参数是QTextFramFormatQ返回值是QTextFrameQ光标会(x)Ud到该Frame?/p>
cursor.insertText("A company", boldFormat);
cursor.insertBlock();//换行
cursor.insertText("321 City Street");
cursor.insertBlock();
cursor.insertText("Industry Park");
cursor.insertBlock();
cursor.insertText("Another country");
cursor.setPosition(topFrame->lastPosition());
cursor.insertText(name, textFormat);
QString line;
foreach (line, address.split("\n")) {
cursor.insertBlock();
cursor.insertText(line);
}//光标被重新移动回来ƈ且写入name address
cursor.insertBlock();
cursor.insertBlock();//twiceQ一ơ表C换行,两次才会(x)产生一个空?/p>
QDate date = QDate::currentDate();
cursor.insertText(tr("Date: %1").arg(date.toString("d MMMM yyyy")),
textFormat);//取日期,insert。。?br /> cursor.insertBlock();
QTextFrameFormat bodyFrameFormat;
bodyFrameFormat.setWidth(QTextLength(QTextLength::PercentageLength, 100));
cursor.insertFrame(bodyFrameFormat);
cursor.insertText(tr("I would like to place an order for the following "
"items:"), textFormat);
cursor.insertBlock();
cursor.insertBlock();//nserts standard text into the order form.
//接下来是一?br />//A QTextTableFormat object, orderTableFormat, is used to hold the type of item and the quantity ordered.
//用来存储orderItems及其数量
QTextTableFormat orderTableFormat;
orderTableFormat.setAlignment(Qt::AlignHCenter);
QTextTable *orderTable = cursor.insertTable(1, 2, orderTableFormat);
QTextFrameFormat orderFrameFormat = cursor.currentFrame()->frameFormat();
orderFrameFormat.setBorder(1);
cursor.currentFrame()->setFrameFormat(orderFrameFormat);
//题外Q关于QTextTable的Spacing?font>Padding在QTextTablecȝ介绍了有个图
//感觉padding即ؓ(f)外围的边距,spacing即ؓ(f)内部边距
cursor = orderTable->cellAt(0, 0).firstCursorPosition();
cursor.insertText(tr("Product"), boldFormat);
cursor = orderTable->cellAt(0, 1).firstCursorPosition();
cursor.insertText(tr("Quantity"), boldFormat);
//d每列的标?font>P Quantity
//不过q样d出来的cell是可以在界面上修改的Q如何防止这点?
//editor->setReadOnly(true);?x)整个面不可~辑Q所以不可用
for (int i = 0; i < orderItems.count(); ++i) {
QPair<QString,int> item = orderItems[i];
int row = orderTable->rows();//当前行数
orderTable->insertRows(row, 1);//在最后添加额外一?br /> cursor = orderTable->cellAt(row, 0).firstCursorPosition();
cursor.insertText(item.first, textFormat);
cursor = orderTable->cellAt(row, 1).firstCursorPosition();
cursor.insertText(QString("%1").arg(item.second), textFormat);
}
//在这D代码后我加了一D代码测试了?br /> cursor.insertText("This is a test");
cursor.setPosition(cursor.currentFrame()->firstPosition());
cursor.insertText("another test");
//
//至于cellAtQ?Q?Q处的背景颜Ԍ是这么改变的
QTextTableCell cell = orderTable->cellAt(0,0);
QTextCharFormat format = cell.format();
format.setBackground(Qt::green);
cell.setFormat(format);
//
//l箋E序里的源代?br />//The cursor is then moved back to topFrame's lastPosition() and more standard text is inserted.
cursor.setPosition(topFrame->lastPosition());//q回到topFrame的正位|开始输?/p>
cursor.insertBlock();
cursor.insertText(tr("Please update my records to take account of the "
"following privacy information:"));
cursor.insertBlock();
//Another QTextTable is inserted, to display the customer's preference regarding offers.
QTextTable *offersTable = cursor.insertTable(2, 2);
cursor = offersTable->cellAt(0, 1).firstCursorPosition();
cursor.insertText(tr("I want to receive more information about your "
"company's products and special offers."), textFormat);
cursor = offersTable->cellAt(1, 1).firstCursorPosition();
cursor.insertText(tr("I do not want to receive any promotional information "
"from your company."), textFormat);
if (sendOffers)
cursor = offersTable->cellAt(0, 0).firstCursorPosition();
else
cursor = offersTable->cellAt(1, 0).firstCursorPosition();
cursor.insertText("X", boldFormat);
//The cursor is moved to insert "Sincerely" along with the customer's name. More blocks are inserted for spacing purposes. The printAction is enabled to indicate that an order form can now be printed.
cursor.setPosition(topFrame->lastPosition());
cursor.insertBlock();
cursor.insertText(tr("Sincerely,"), textFormat);
cursor.insertBlock();
cursor.insertBlock();
cursor.insertBlock();
cursor.insertText(name);
printAction->setEnabled(true);
}
其实ȝ下的话,整个界面的Ş成主要依赖于cursor的移动和insert
Ud比如q样
cursor = offersTable->cellAt(0, 1).firstCursorPosition();
或?br />cursor.setPosition(topFrame->lastPosition());{等
输入主要依靠QTextCursor的四个函数来完成?br />void insertText ( const QString & text, const QTextCharFormat & format )
QTextFrame * insertFrame ( const QTextFrameFormat & format )
void insertBlock ( const QTextBlockFormat & format, const QTextCharFormat & charFormat )
QTextTable * insertTable ( int rows, int columns, const QTextTableFormat & format )
5.
关于q一句分析一下流E?br />buttonBox ?acceptedQ)信号?x)触发DetailsDialog的verifyQ)槽,该槽函数?x)执行Dialog的accept() or reject()
void QDialog::accept () [virtual slot]
Hides the modal dialog and sets the result code to Accepted.
void QDialog::reject () [virtual slot]
Hides the modal dialog and sets the result code to Rejected.
void QDialog::done ( int r ) [virtual slot]
Closes the dialog and sets its result code to r. If this dialog is shown with exec(), done() causes the local event loop to finish, and exec() to return r.
//TODOQ?br />最后的print界面用的QPrintDialog来实玎ͼ有空可以看下
QTextCursor以及相关q需要进一步学?br />openDialog函数里,不执行dialog.exec()
用dialog.show(),H口没有show出来
再说下功能:(x)
5各QGroupBox分别对应5各方面的功能Q也同时对应着QLineEidt?个函?br />从第一个开始说P(x)
昄斚w的,看下c里面自定义的枚举,正好对应Echo 的ComboxBox?个选项
enum QLineEdit::EchoMode
This enum type describes how a line edit should display its contents.
Constant Value Description
QLineEdit::Normal 0 Display characters as they are entered. This is the default.
QLineEdit::NoEcho 1 Do not display anything. This may be appropriate for passwords where even the length of the password should be kept secret.
QLineEdit::Password 2 Display asterisks instead of the characters actually entered.
QLineEdit::PasswordEchoOnEdit 3 Display characters as they are entered while editing otherwise display asterisks.
使用的函数是Q?br />void setEchoMode ( EchoMode )
相关的函数查了下q有q两?br />1.displayText : const QString
This property holds the displayed text.
If echoMode is Normal this returns the same as text(); if EchoMode is Password or PasswordEchoOnEdit it returns a string of asterisks text().length() characters long, e.g. "******"; if EchoMode is NoEcho returns an empty string, "".
By default, this property contains an empty string.
2.text : QString
This property holds the line edit's text.
Setting this property clears the selection, clears the undo/redo history, moves the cursor to the end of the line and resets the modified property to false. The text is not validated when inserted with setText().
The text is truncated to maxLength() length.
By default, this property contains an empty string.
思义QdisplayTextq回的是昄内容Q如果时密码模式Q那么返?*************星号
W二个:(x)
Validator使用的函数是
void QLineEdit::setValidator ( const QValidator * v )
Sets this line edit to only accept input that the validator, v, will accept. This allows you to place any arbitrary constraints on the text which may be entered.
If v == 0, setValidator() removes the current input validator. The initial setting is to have no input validator (i.e. any input is accepted up to maxLength()).
See also validator(), QIntValidator, QDoubleValidator, and QRegExpValidator.
看下E序里是怎么用的
case 0:
validatorLineEdit->setValidator(0);
break;
case 1:
validatorLineEdit->setValidator(new QIntValidator(
validatorLineEdit));
break;
case 2:
validatorLineEdit->setValidator(new QDoubleValidator(-999.0,
999.0, 2, validatorLineEdit));
}
是QLineEdit内只能输入整敎ͼ0.01_ֺ点数。可以看到还可以利用正则控制输入的内容:(x)
QRegExp rx("\\d{,6}");
validatorLineEdit->setValidator(new QRegExpValidator(rx,validatorLineEdit));
q样只能输入最?各数字了Q再配合前面的密码模式输入就可以用来讄密码了:(x)Q?br />W三个:(x)讄寚w方式
W三各用到的函数?br />void setAlignment ( Qt::Alignment flag )
alignment : Qt::Alignment
This property holds the alignment of the line edit.
Both horizontal and vertical alignment is allowed here, Qt::AlignJustify will map to Qt::AlignLeft.
By default, this property contains a combination of Qt::AlignLeft and Qt::AlignVCenter.
非常单,直接看枚丄cd
enum Qt::AlignmentFlag
flags Qt::Alignment
This enum type is used to describe alignment. It contains horizontal and vertical flags that can be combined to produce the required effect.
The TextElideMode enum can also be used in many situations to fine-tune the appearance of aligned text.
The horizontal flags are:
Constant Value Description
Qt::AlignLeft 0x0001 Aligns with the left edge.
Qt::AlignRight 0x0002 Aligns with the right edge.
Qt::AlignHCenter 0x0004 Centers horizontally in the available space.
Qt::AlignJustify 0x0008 Justifies the text in the available space.
The vertical flags are:
Constant Value Description
Qt::AlignTop 0x0020 Aligns with the top.
Qt::AlignBottom 0x0040 Aligns with the bottom.
Qt::AlignVCenter 0x0080 Centers vertically in the available space.
You can use only one of the horizontal flags at a time. There is one two-dimensional flag:
Constant Value Description
Qt::AlignCenter AlignVCenter | AlignHCenter Centers in both dimensions.
You can use at most one horizontal and one vertical flag at a time. Qt::AlignCenter counts as both horizontal and vertical.
Three enum values are useful in applications that can be run in right-to-left mode:
Constant Value Description
Qt::AlignAbsolute 0x0010 If the widget's layout direction is Qt::RightToLeft (instead of Qt::LeftToRight, the default), Qt::AlignLeft refers to the right edge and Qt::AlignRight to the left edge. This is normally the desired behavior. If you want Qt::AlignLeft to always mean "left" and Qt::AlignRight to always mean "right", combine the flag with Qt::AlignAbsolute.
Qt::AlignLeading AlignLeft Synonym for Qt::AlignLeft.
Qt::AlignTrailing AlignRight Synonym for Qt::AlignRight.
Masks:
Constant Value
Qt::AlignHorizontal_Mask AlignLeft | AlignRight | AlignHCenter | AlignJustify | AlignAbsolute
Qt::AlignVertical_Mask AlignTop | AlignBottom | AlignVCenter
Conflicting combinations of flags have undefined meanings.
The Alignment type is a typedef for QFlags<AlignmentFlag>. It stores an OR combination of AlignmentFlag values.
W四个:(x)可以用来控制一些输入格式,可以无须借助正则
用到函数主要?br />void setInputMask ( const QString & inputMask )
直接看介l?br />inputMask : QString
This property holds the validation input mask.
If no mask is set, inputMask() returns an empty string.
Sets the QLineEdit's validation mask. Validators can be used instead of, or in conjunction with masks; see setValidator().
Unset the mask and return to normal QLineEdit operation by passing an empty string ("") or just calling setInputMask() with no arguments.
The table below shows the characters that can be used in an input mask. A space character, the default character for a blank, is needed for cases where a character is permitted but not required.
Character Meaning
A ASCII alphabetic character required. A-Z, a-z.
a ASCII alphabetic character permitted but not required.
N ASCII alphanumeric character required. A-Z, a-z, 0-9.
n ASCII alphanumeric character permitted but not required.
X Any character required.
x Any character permitted but not required.
9 ASCII digit required. 0-9.
0 ASCII digit permitted but not required.
D ASCII digit required. 1-9.
d ASCII digit permitted but not required (1-9).
# ASCII digit or plus/minus sign permitted but not required.
H Hexadecimal character required. A-F, a-f, 0-9.
h Hexadecimal character permitted but not required.
B Binary character required. 0-1.
b Binary character permitted but not required.
> All following alphabetic characters are uppercased.
< All following alphabetic characters are lowercased.
! Switch off case conversion.
\ Use \ to escape the special characters listed above to use them as separators.
The mask consists of a string of mask characters and separators, optionally followed by a semicolon and the character used for blanks. The blank characters are always removed from the text after editing.
Examples:
Mask Notes
000.000.000.000;_ IP address; blanks are _.
HH:HH:HH:HH:HH:HH;_ MAC address
0000-00-00 ISO Date; blanks are space
>AAAAA-AAAAA-AAAAA-AAAAA-AAAAA;# License number; blanks are - and all (alphabetic) characters are converted to uppercase.
To get range control (e.g., for an IP address) use masks together with validators.
Access functions:
QString inputMask () const
void setInputMask ( const QString & inputMask )
See also maxLength.
看下E序用到的地方:(x)
switch (index) {
case 0:
inputMaskLineEdit->setInputMask("");
break;
case 1:
inputMaskLineEdit->setInputMask("+99 99 99 99 99;_");
break;
case 2:
inputMaskLineEdit->setInputMask("0000-00-00");
inputMaskLineEdit->setText("00000000");
inputMaskLineEdit->setCursorPosition(0);
break;
case 3:
inputMaskLineEdit->setInputMask(">AAAAA-AAAAA-AAAAA-AAAAA-AAAAA;#");
其中分号后面跟的W号?x)代替掉前面的那些通配W?br />比如选到License Key QQLIneEdit内容变ؓ(f)
#####-#####-#####-#####-#####
输入时只能输入字母,同时-?x)自动蟩q,不可改变Q不被删除,M试下q道了哈哈
5.
很简单,讄内容是否可更?br />readOnly : bool
This property holds whether the line edit is read only.
In read-only mode, the user can still copy the text to the clipboard, or drag and drop the text (if echoMode() is Normal), but cannot edit it.
QLineEdit does not show a cursor in read-only mode.
By default, this property is false.
几个函数l合使用Q功能很强大
该例子有两个主要的类Q?br />ShapeItem is a custom widget representing one single shape item.
SortingBox inherits from QWidget and is the application's main widget.
1.SortingBox
SortingBoxc里重新实现了很多eventQ用途如下:(x)
The event() function provides tooltips, the resize() function makes sure the application appears consistently when the user resizes the main widget, and the paintEvent() function displays the shape items within the SortingBox widget. The mouse event handlers are reimplemented to make the user able to move the items around.
三个U有的槽函数分别对应创徏三种囑Ş
在构造函数里调用三个函数Q?br />initialItemPosition(), initialItemColor() and createToolButton()
看名字就知道在做什么了
2.
要显Ctooltip必须要知道鼠标移动事Ӟ默认在不按下键时是不记录鼠标轨迹的,因此需要设|下
setMouseTracking(true);
To be able to show the appropiate tooltips while the user is moving the cursor around, we need to enable mouse tracking for the widget.
If mouse tracking is disabled (the default), the widget only receives mouse move events when at least one mouse button is pressed while the mouse is being moved. If mouse tracking is enabled, the widget receives mouse move events even if no buttons are pressed.
3.如何d的三角ŞQ矩形,椭圆
矩ŞQ椭圆用QPainter的函数就可以了,三角形用drawLineMơ,每次M角Ş是不是太费劲了那Q或者如果遇到其他不规则的图形,怎么d来的呢?
q里qCQPainterPathcM
先看个addRect函数
再看个addEllipse
再来个贝泽尔?img height="263" alt="" src="http://www.shnenglu.com/images/cppblog_com/izualzhy/QPainterPath__cubicTo.png" width="731" border="0" />U的
先定义曲U,然后用QPainter::drawPath()O(jin)K?br />有一个问题是QdrawPathQ)q不能指定position
看下定义
因此在想要在某个点开始画出想要的曲线Q先Ud坐标p?br /> foreach (ShapeItem shapeItem, shapeItems) {
//! [8] //! [9]
painter.translate(shapeItem.position());
//! [9] //! [10]
painter.setBrush(shapeItem.color());
painter.drawPath(shapeItem.path());
painter.translate(-shapeItem.position());
}
q么做的解释Q?br />The painter will by default draw all the shape items at position (0,0) in the SortingBox widget. The QPainter::translate() function translates the coordinate system by the given offset, making each shape item appear at its defined position. But remember to translate the coordinate system back when the item is drawn, otherwise the next shape item will appear at a position relative to the item we drawed last.
4.如何实现UdQ?br />思考一下,肯定是在mousePressEvent,mouseMoveEvent,moutReleaseEvent上修攏V?br />而且说是UdQ其实是完全重绘了一遍整个widget?br />那么Q怎么知道当前鼠标点在哪个囑Ş上呢Q?br />其实q个问题比之前我想的要简单:(x)
E序利用了如下函敎ͼ(x)
int SortingBox::itemAt(const QPoint &pos)
{
for (int i = shapeItems.size() - 1; i >= 0; --i) {
const ShapeItem &item = shapeItems[i];
if (item.path().contains(pos - item.position()))
return i;
}
return -1;
}
循环遍历每个shapwItemQ逆序遍历的原因是当这个点在多个shapeitem上时Q返回最上面的一个,利用QPainterPath的函数contains
bool QPainterPath::contains ( const QPointF & point ) const
Returns true if the given point is inside the path, otherwise returns false.
记录鼠标Ud前后的偏U量Q设|给当前的shapeItemQ然后updateQ)重绘?br />值得注意的是对shapeItemsQ即存储囑Ş的列表的修改Q假设要以动的图形在列表里烦引是indexQ调用下列语?br /> shapeItems.move(index, shapeItems.size() - 1);
是当前修改位|的囑Ş跑到列表最后?br />5.如何实现toolTops的?
bool SortingBox::event(QEvent *event)
{
//! [5] //! [6]
if (event->type() == QEvent::ToolTip) {
QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
int index = itemAt(helpEvent->pos());
if (index != -1) {
QToolTip::showText(helpEvent->globalPos(), shapeItems[index].toolTip());
} else {
QToolTip::hideText();
event->ignore();
}
return true;
}
return QWidget::event(event);
}
直接看Qt assistant的解?br />If the type is QEvent::ToolTip, we cast the event to a QHelpEvent, otherwise we propagate the event using the QWidget::event() function.
The QHelpEvent class provides an event that is used to request helpful information about a particular point in a widget.
For example, the QHelpEvent::pos() function returns the event's position relative to the widget to which the event is dispatched. Here we use this information to determine if the position of the event is contained within the area of any of the shape items. If it is, we display the shape item's tooltip at the position of the event. If not, we hide the tooltip and explicitly ignore the event. This makes sure that the calling code does not start any tooltip specific modes as a result of the event. Note that the QToolTip::showText() function needs the event's position in global coordinates provided by QHelpEvent::globalPos().
该例子由两个主要的类
MainWindowQpublic QMainWindow
PreviewForm: public QDialog
1.
文本输入界面使用的QTextEditQ通过 setCentralWidget(textEdit);而设定ؓ(f)MainWindow的主H口Q应该是很熟(zhn)这个了~~
QTextEdit有一个属性是
enum QTextOption::WrapMode
This enum describes how text is wrapped in a document.
Constant Value Description
QTextOption::NoWrap 0 Text is not wrapped at all.
QTextOption::WordWrap 1 Text is wrapped at word boundaries.
QTextOption::ManualWrap 2 Same as QTextOption::NoWrap
QTextOption::WrapAnywhere 3 Text can be wrapped at any point on a line, even if it occurs in the middle of a word.
QTextOption::WrapAtWordBoundaryOrAnywhere 4 If possible, wrapping occurs at a word boundary; otherwise it will occur at the appropriate point on the line, even in the middle of a word.
表示在行末如何换行或者不换行?br>2.
׃~码方式很多Qؓ(f)了菜单看上ȝ观些Q要讄一下那些匹配到一块,于是用到了QRegExp
q里用的正则是很单的Q我也只看了下用到的两个函数
A?br>bool QRegExp::exactMatch ( const QString & str ) const
Returns true if str is matched exactly by this regular expression; otherwise returns false. You can determine how much of the string was matched by calling matchedLength().
For a given regexp string R, exactMatch("R") is the equivalent of indexIn("^R$") since exactMatch() effectively encloses the regexp in the start of string and end of string anchors, except that it sets matchedLength() differently.
For example, if the regular expression is blue, then exactMatch() returns true only for input blue. For inputs bluebell, blutak and lightblue, exactMatch() returns false and matchedLength() will return 4, 3 and 0 respectively.
q个表示的是要完全匹配,而不是从中间开始。类gPython里正则表辑ּ的search()和matchQ)
B?br>QString QRegExp::cap ( int nth = 0 ) const
Returns the text captured by the nth subexpression. The entire match has index 0 and the parenthesized subexpressions have indexes starting from 1 (excluding non-capturing parentheses).
通过在rx里添加括h看返回|?br>匚w好了之后?x)同时生一个intcd的rank|加在codec的名字前作ؓ(f)keyQcodec作ؓ(f)valuel成QMap
3.
在private里定义了QList<QTextCodec *> codecs;
刚定义的QMap通过valuesQ)函数赋给该私有变量,注意valuesQ)函数的描qͼ(x)
QList<T> QMap::values () const
Returns a list containing all the values in the map, in ascending order of their keys. If a key is associated with multiple values, all of its values will be in the list, and not just the most recently inserted one.
?x)有一个顺序的问题Q这也是我们drank的原因了~~
q样赋g后,QList codecs里就是排序之后的了~?br>得先忙工作的东西了,有空要再研究?/p>
QAbstractScrollArea is a low-level abstraction of a scrolling area. The area provides a central widget called the viewport, in which the contents of the area is to be scrolled (i.e, the visible parts of the contents are rendered in the viewport).
Next to the viewport is a vertical scroll bar, and below is a horizontal scroll bar. When all of the area contents fits in the viewport, each scroll bar can be either visible or hidden depending on the scroll bar's Qt::ScrollBarPolicy. When a scroll bar is hidden, the viewport expands in order to cover all available space. When a scroll bar becomes visible again, the viewport shrinks in order to make room for the scroll bar.
It is possible to reserve a margin area around the viewport, see setViewportMargins(). The feature is mostly used to place a QHeaderView widget above or beside the scrolling area. Subclasses of QAbstractScrollArea should implement margins.1
1.
fontMetrics().width(QLatin1Char('9'))
q回只有一个字W?#8216;9’时的合理宽度~~
2.
void QAbstractScrollArea::setViewportMargins ( int left, int top, int right, int bottom )
q个函数一直弄混了Q该函数实际上是创徏了四个margin
setViewportMargins(lineNumberAreaWidth(), 0, 0, 0);
例如该语句即是在左边创徏一个margin~~虽然只传q了一个int|但viewport周围的margin是环l整个viewport的,所以另一条边是固定大的Q早惛_q点׃?x)看不明白了。。。)
Shape Analog Clock example
1.
Qt::FramelessWindowHint可以使窗口去掉关?最大化 最化{,但是需要重新自定义move{事?br>该flag在Qt里介l:(x)
Produces a borderless window. The user cannot move or resize a borderless window via the window system
在这个例子里于是我们需要自定义mouseMoveEvent,mousePressEventQ原文如下:(x)
We inform the window manager that the widget is not to be decorated with a window frame by setting the Qt::FramelessWindowHint flag on the widget. As a result, we need to provide a way for the user to move the clock around the screen.
该例子实现后可以在桌面上拖动一个类g表的widgetQ同时没有边框,很美观,那么定义mouseMoveEvent()Ӟ我们如何定该widget应当moveC么地方呢Q?br>例子里定一个一个private data Q?br>QPoint dragPosition;
在mousePressEvent?br>dragPosition = event->globalPos() - frameGeometry().topLeft();
在mouseMoveEvent?br>move(event->globalPos() - dragPosition);
x鼠标按下时的位置与控件左上的坐标距离作ؓ(f)一个偏U量
原文介绍如下Q?br>If the left mouse button is pressed over the widget, we record the displacement in global (screen) coordinates between the top-left position of the widget's frame (even when hidden) and the point where the mouse click occurred. This displacement will be used if the user moves the mouse while holding down the left button. Since we acted on the event, we accept it by calling its accept() function.
注意q里时globalPos()~~
2.sizeHint()
刚开始没有弄懂ؓ(f)什么要定义sizeHint()
L后对比下囑փ发现囑֤了不,才明白在囑փ未指定大时W一ơshow的时候会(x)自动调用sizeHintQ)
例子中说明如?br>Finally, we implement the sizeHint() for the widget so that it is given a reasonable default size when it is first shown:LsizeHint函数?br>
用了sizeHint的就比较观?br>3.mask
那么如何是窗口呈Cؓ(f)一个圆形的呢?
其实H口q是矩Ş的,不过通过mask设ؓ(f)一部分可见Q一部分透明?br>setMask有两UŞ式,不过作用都是cM?br>void QWidget::setMask ( const QBitmap & bitmap )
Causes only the pixels of the widget for which bitmap has a corresponding 1 bit to be visible
void QWidget::setMask ( const QRegion & region )
Causes only the parts of the widget which overlap region to be visible.
x区域内可见,其余不可见?br>另外一个关于透明性的函数?br>void setWindowOpacity ( qreal level )
windowOpacity : double
This property holds the level of opacity for the window.
The valid range of opacity is from 1.0 (completely opaque) to 0.0 (completely transparent).
该函数控制的是整个widget的透明性~
如果setMaskQ)与setWindowOpacityQ)一L(fng)了,QREgion外仍是透明的,不过mask的区域透明度因为setWindowOpacityQ)改变了?br>q是我用了该函数之后的例?br> 可以看到变得透明?br>q张囑֯比就更明显了
4.如何按下鼠标右键弹出Action的?
直接new一个QAction出来然后addp了~?br>估计是因为在q种widget下没有其他地Ҏ(gu)默认放在右键里了,需要进一步学?fn)才能确定~?/p>
在Qt4.0里Scribble example里画U条是先draw在一个image上,image在通过drawImagedwidget上,l出了这L(fng)理由
At this point, you might wonder why we don't just draw directly onto the widget instead of drawing in a QImage and copying the QImage onto screen in paintEvent(). There are at least three good reasons for this:
The window system requires us to be able to redraw the widget at any time. For example, if the window is minimized and restored, the window system might have forgotten the contents of the widget and send us a paint event. In other words, we can't rely on the window system to remember our image.
Qt normally doesn't allow us to paint outside of paintEvent(). In particular, we can't paint from the mouse event handlers. (This behavior can be changed using the Qt::WA_PaintOnScreen widget attribute, though.)
If initialized properly, a QImage is guaranteed to use 8-bit for each color channel (red, green, blue, and alpha), whereas a QWidget might have a lower color depth, depending on the monitor configuration. This means that if we load a 24-bit or 32-bit image and paint it onto a QWidget, then copy the QWidget into a QImage again, we might lose some information.
image比widget要稍大一点,理由如下
When the user starts the Scribble application, a resize event is generated and an image is created and displayed in the scribble area. We make this initial image slightly larger than the application's main window and scribble area, to avoid always resizing the image when the user resizes the main window (which would be very inefficient). But when the main window becomes larger than this initial size, the image needs to be resized.
当需要重l的事gpaintEventӞ通过传给updateQ)一个参数可能会(x)提高效率Q当然前提是你知道这个参?br>We could call the update() function with no parameter, but as an easy optimization we pass a QRect that specifies the rectangle inside the scribble are needs updating, to avoid a complete repaint of the widget.
例如q里传入的是Q鼠标新ȝU段 与笔的大组成的一个矩形区域。这样只?x)重新绘制这里了~?br> Painter painter(&image);
painter.setPen(QPen(myPenColor, myPenWidth, Qt::SolidLine, Qt::RoundCap,
Qt::RoundJoin));
painter.drawLine(lastPoint, endPoint);
modified = true;
int rad = (myPenWidth / 2) + 2;
update(QRect(lastPoint, endPoint).normalized()
.adjusted(-rad, -rad, +rad, +rad));
当有多个signalq接C个槽Ӟ例如在保存文件时Q给出的QAction?BMP JPG JPEG {,此时只需要一个saveQ)的槽函数QsaveQ)函数需要知道是哪个signal发送过来,此时根据QObject * QObject::sender () const [protected]来判断sender
该函Cl如下:(x)
QObject * QObject::sender () const [protected]
Returns a pointer to the object that sent the signal, if called in a slot activated by a signal; otherwise it returns 0. The pointer is valid only during the execution of the slot that calls this function from this object's thread context.
The pointer returned by this function becomes invalid if the sender is destroyed, or if the slot is disconnected from the sender's signal.
Warning: This function violates the object-oriented principle of modularity. However, getting access to the sender might be useful when many signals are connected to a single slot.
Warning: As mentioned above, the return value of this function is not valid when the slot is called via a Qt::DirectConnection from a thread different from this object's thread. Do not use this function in this type of scenario.
具体scribble 里代码如?br> void MainWindow::save()
{
QAction *action = qobject_cast<QAction *>(sender());
QByteArray fileFormat = action->data().toByteArray();
saveFile(fileFormat);
}
W一句:(x)
QAction *action = qobject_cast<QAction *>(sender());
虽然不知道senderQ)具体是哪一个QActionQ但我们知道肯定是一个QActionQ因此可以castq来?br>用static_cast<>也是可以的,q里使用qobject_cast的原因例子里说明如下
but as a defensive programming technique we use a qobject_cast(). The advantage is that if the object has the wrong type, a null pointer is returned. Crashes due to null pointers are much easier to diagnose than crashes due to unsafe casts.
W二句:(x)
QAction里有setdataQ) ?dataQ)两个函数作用是这L(fng)
1.
QVariant QAction::data () const
Returns the user data as set in QAction::setData.
2.
void QAction::setData ( const QVariant & userData )
Sets the action's internal data to the given userData.
在创建QAction的时候,我们setDataQ)
foreach (QByteArray format, QImageWriter::supportedImageFormats()) {
QString text = tr("%1...").arg(QString(format).toUpper());
QAction *action = new QAction(text, this);
action->setData(format);
connect(action, SIGNAL(triggered()), this, SLOT(save()));
saveAsActs.append(action);
}
此时通过ction->data().toByteArray();取出?br>然后传给W三句,saveFile函数q道该存ؓ(f)哪种格式?/p>
psQ?br>在界面编E里Q例如写一个saveQ)函数Q可能saveFileQ)才是实现保存文g的作用的?br>但点击saveactionӞ调用saveQ)Q实际上需要判断各U情况,例如文g名合?同名{,需要根据不同情况弹Z同的对话框,当全都判断true后,才会(x)调用saveFileQ)函数Q这可能是跟之前自qE差别比较大的情况了~~