-----------------------------------
QString初始化:
-----------------------------------
QString s1 = "汉语";
QString s2("漢語");
QString s3 = tr("中文")
QString s4 = QStringLiteral("中文");//只要字符串不需要翻译,请关注这个
QString s5 = QString::fromWCharArray(L"中文");
QString s6 = u8"中文";//C++11
QString s7 = tr(u8"中文")
QStringLiteral("dbzhang800");
QLatin1String("dbzhang800");
前者占用的常量区比较多,程序体积会稍微大一点。
QLatin1String:避免操作符 "==" 中隐含的 malloc
QStringRef:没有 malloc 的字符串操作 => QString::midRef()、QString::leftRef()与QString::rightRef()
QString::reserve 与 QString::squeeze
=> 提前调用 QString::reserve 来分配额外的内存,这样每次调用 QString::append() 不会导致一个 malloc。
额外的内存可以使用 QString::squeeze 来回收。
QStringBuilder:字符串的快速连接
(1)直接方式就是包含QStringBuilder ,当你在任何地方用到它的时候。然后当连接字符串的时候,用'%'代替'+'。
#include
QString hello("hello");
QStringRef el(&hello, 2, 3);
QLatin1String world("world");
QString message = hello % el % world % QChar('!');
(2)全局的方式,定义一个宏定义。然后用用'%'代替'+'
#define QT_USE_FAST_CONCATENATION
(3)最方便,但是并不是所有代码都会兼容。就是包含两个宏定义即可
#define QT_USE_FAST_CONCATENATION
#define QT_USE_FAST_OPERATOR_PLUS
然后所有的'+'就会被当做QStringBuilder 的'%'执行
(!)5.0,这个宏已被新的QT_USE_QSTRINGBUILDER宏所替代
-----------------------------------
QString输出,格式化及格式化输出:
-----------------------------------
(1)QTextStream
#include
QTextStream cin(stdin, QIODevice::ReadOnly);
QTextStream cout(stdout, QIODevice::WriteOnly);
QTextStream cerr(stderr, QIODevice::WriteOnly);
QString str="test %1,%2";
str=str.arg("This is arg0,测试中文").arg("This is arg1");
cout< (2)qPrintable ==>相当于QString.toLocal8Bit().constData printf("%s\n",qPrintable(str)); 进一步说明: QByteArray::constData可转为char* QString str(" fa fkajfj "); str=str.trimmed();==>去前后空格 ----------------------------------- QStringMatcher:字符串快速匹配 ----------------------------------- ==>纯文本查找,不能含正则表达式 QStringMatcher matcher("1234"); int pos=matcher.indexIn(QLatin1String("4781234")); ----------------------------------- File读写: ----------------------------------- (1)文本文件: QFile inputFile(QStringLiteral("f:/opencv/training/sample/pos-data.txt")); inputFile.open(QIODevice::ReadOnly); QTextStream in(&inputFile); QString line = in.readAll(); inputFile.close(); ui->textEdit->setPlainText(line); QTextCursor cursor = ui->textEdit->textCursor(); cursor.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor, 1); ui->textEdit->find(searchString, QTextDocument::FindWholeWords); (2)二进制文件: //read from file QFile file(fileName); if (!file.open(QIODevice::ReadOnly)) {...} QDataStream in(&file); in >> pairs; if (pairs.isEmpty()) {...} //write to file QFile file(fileName); if (!file.open(QIODevice::WriteOnly)) {...} QDataStream out(&file); out << pairs; file.close(); (3)文件对话框 QString fileName = QFileDialog::getSaveFileName(this); if (!fileName.isEmpty()){....} -------------------- 信号: -------------------- Q_OBJECT signals: void finishedAnalysis(); private slots: void handleReply(QNetworkReply*); emit finishedAnalysis(); QObject::connect(m_network, SIGNAL(finished(QNetworkReply*)),this, SLOT(handleReply(QNetworkReply*)));//注意形参一致 -------------------- Q_PROPERTY -------------------- Q_PROPERTY(type name READ getFunction [WRITE setFunction][RESET resetFunction][DESIGNABLE bool][SCRIPTABLE bool][STORED bool]) class Test : public QObject { Q_OBJECT Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled) public: Test(QObject *parent = 0) : QObject(parent) {} virtual ~Test(){} void setEnabled(bool e) { enabled = e; } bool isEnabled() const { return enabled; } private: bool enabled; }; int main(){ Test *test = new Test; test->setProperty("enabled", true);//===>可用QObject::setProperty(); //test->setEnabled(true); //ok also work if(test->property("enabled").toBool()) } -------------------- Q_UNUSED : -------------------- Q_UNUSED(d) ==>避免编译器报warning -------------------- QT_BEGIN_NAMESPACE /QT_END_NAMESPACE : -------------------- 可以降低各个文件编译时的关联度,不会在改动了一下部分类的时候,引 发其他大量文件的重新编译, 在做小工程的时候没什么区别,但是做大了,编译一次需要好几个小时的时候,这样做的优势就显现出来了 .h文件: QT_BEGIN_NAMESPACE class QNetworkAccessManager; class QNetworkReply; class QNetworkDiskCache; QT_END_NAMESPACE .cpp文件: #include #include #include #include 带泛型的在.h文件里也要用include,如: QFutureWatcher -------------------- QList: -------------------- QList m_imageQueue << img; foreach(const QRgb & triplet, m_watcher->future().results()){} //QList遍历 m_imageQueue << img m_imageQueue.pop_back(); //容器类的内存管理,当容器内存放的是指针时... qDeleteAll(childItems); ==>childItems里存放的是指针,一次全部释放动态内存 -------------------- QRgb: -------------------- rTot += qRed(triplet); bTot += qBlue(triplet); gTot += qGreen(triplet); -------------------- QtConcurrent/Qt多线程编程 -------------------- #include m_watcher->setFuture(QtConcurrent::mapped(m_imageQueue, averageRGB)); QT通过三种形式提供了对线程的支持。 它们分别是,一、平台无关的线程类,二、线程安全的事件投递,三、跨线程的信号-槽连接。 (1)常用线程类: QThread 提供了开始一个新线程的方法 QThreadStorage 提供逐线程数据存储 QMutex 提供相互排斥的锁,或互斥量 QMutexLocker 是一个便利类,它可以自动对QMutex加锁与解锁 QReadWriterLock 提供了一个可以同时读操作的锁 QReadLocker与QWriteLocker 是便利类,它自动对QReadWriteLock加锁与解锁 QSemaphore 提供了一个整型信号量,是互斥量的泛化 QWaitCondition 提供了一种方法,使得线程可以在被另外线程唤醒之前一直休眠。 Qt 高级线程类: QtConcurrent 开启线程事务 QFutureWatcher 观测线程状态 QFuture 线程启动类 QThread创建线程 Asynchronous Run 提供一个方式来运行一个 函数在一个独立的线程 Concurrent Filter and Filter-Reduce 提供同时发生的过滤器 和filter-reduce Concurrent Map and Map-Reduce 提供同时发生的Map和MapReduceQAtomicInt平台独立的原子操作在整数。 QAtomicPointer模板类,提供 平台独立的原子操作在指针上。QFuture代表一个同步的计算的结果。 QFutureSynchronizer方便类,简单化QFuture同步。 (2)线程类定义: class MyThread : public QThread { Q_OBJECT protected: void run(); }; void MyThread::run(){...} (3)QtConcurrent创建线程: QtConcurrent 创建线程的方法比较多, 而且QtConcurrent 本身比较特殊,若系统有空闲线程时,它会调度空闲线程,无空闲线程时将会创建一个线程。 (注意:QtConcurrent 创建线程归QthreadPool管理,若超过最大线程数,将会进入队列等待),QtConcurrent创建线程的方法多种,以下举例map函数: QImage scale(const QImage &image) { qDebug() < < "Scaling image in thread" << QThread::currentThread(); return image.scaled(QSize(100, 100), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); } int main(int argc, char *argv[]) { QApplication app(argc, argv); const int imageCount = 20; // Create a list containing imageCount images. QList images; for (int i = 0; i < imageCount; ++i) images.append(QImage(1600, 1200, QImage::Format_ARGB32_Premultiplied)); // Use QtConcurrentBlocking::mapped to apply the scale function to all the // images in the list. QList thumbnails = QtConcurrent::blockingMapped(images, scale); return 0; } (4)Qt线程同步: ===QReadWriterLock:==== QReadWriteLock lock; void ReaderThread::run() { lock.lockForRead(); read_file(); lock.unlock(); } void WriterThread::run() { lock.lockForWrite(); write_file(); lock.unlock(); } ===QSemaphore:===QSemaphore 是QMutex的一般化,它可以保护一定数量的相同资源 const int DataSize = 100000; const int BufferSize = 8192; char buffer[BufferSize]; QSemaphore freeBytes(BufferSize); QSemaphore usedBytes; class Producer : public QThread { public: void run(); }; void Producer::run() { qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); for (int i = 0; i < DataSize; ++i) { freeBytes.acquire(); buffer[i % BufferSize] = "ACGT"[(int)qrand() % 4]; usedBytes.release(); } } class Consumer : public QThread { public: void run(); }; void Consumer::run() { for (int i = 0; i < DataSize; ++i) { usedBytes.acquire(); fprintf(stderr, "%c", buffer[i % BufferSize]); freeBytes.release(); } fprintf(stderr, "\n"); } int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); Producer producer; Consumer consumer; producer.start(); consumer.start(); producer.wait(); consumer.wait(); return 0; } ===QWaitCondition:===一个或多个线程可以阻塞等待一QWaitCondition ,用wakeOne()或wakeAll()设置一个条件。wakeOne()随机唤醒一个,wakeAll()唤醒所有。 const int DataSize = 100000; const int BufferSize = 8192; char buffer[BufferSize]; QWaitCondition bufferNotEmpty; QWaitCondition bufferNotFull; QMutex mutex; int numUsedBytes = 0; class Producer : public QThread { public: void run(); }; void Producer::run() { qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); for (int i = 0; i < DataSize; ++i) { mutex.lock(); if (numUsedBytes == BufferSize) bufferNotFull.wait(&mutex); mutex.unlock(); buffer[i % BufferSize] = "ACGT"[(int)qrand() % 4]; mutex.lock(); ++numUsedBytes; bufferNotEmpty.wakeAll(); mutex.unlock(); } } class Consumer : public QThread { public: void run(); }; void Consumer::run() { for (int i = 0; i < DataSize; ++i) { mutex.lock(); if (numUsedBytes == 0) bufferNotEmpty.wait(&mutex); mutex.unlock(); fprintf(stderr, "%c", buffer[i % BufferSize]); mutex.lock(); --numUsedBytes; bufferNotFull.wakeAll(); mutex.unlock(); } fprintf(stderr, "\n"); } int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); Producer producer; Consumer consumer; producer.start(); consumer.start(); producer.wait(); consumer.wait(); return 0; } -------------------- Qt多线程解决方案 -------------------- 一次调用 在另一个线程中运行一个函数,函数完成时退出线程 编写函数,使用QtConcurrent::run 运行它 派生QRunnable,使用QThreadPool::globalInstance()->start() 运行它 派生QThread,重新实现QThread::run() ,使用QThread::start() 运行它 ==>QThreadPool::globalInstance()->start(QRunable子类); 一次调用 需要操作一个容器中所有的项。使用处理器所有可用的核心。一个常见的例子是从图像列表生成缩略图。 QtConcurrent 提供了map()函你数来将操作应用到容器中的每一个元素,提供了fitler()函数来选择容器元素,以及指定reduce函数作为选项来组合剩余元素。 一次调用 一个耗时运行的操作需要放入另一个线程。在处理过程中,状态信息需要发送会GUI线程。 使用QThread,重新实现run函数并根据需要发送信号。使用信号槽的queued连接方式将信号连接到GUI线程的槽函数。 持久运行 生存在另一个线程中的对象,根据要求需要执行不同的任务。这意味着工作线程需要双向的通讯。 派生一个QObject对象并实现需要的信号和槽,将对象移动到一个运行有事件循环的线程中并通过queued方式连接的信号槽进行通讯。 持久运行 生存在另一个线程中的对象,执行诸如轮询端口等重复的任务并与GUI线程通讯。 同上,但是在工作线程中使用一个定时器来轮询。尽管如此,处理轮询的最好的解决方案是彻底避免它。有时QSocketNotifer是一个替代。 ================== Qt多线程替代方案: QEventLoop::processEvents() 在一个耗时的计算操作中反复调用QEventLoop::processEvents() 可以防止界面的假死。尽管如此,这个方案可伸缩性并不太好,因为该函数可能会被调用地过于频繁或者不够频繁。 QTimer 后台处理操作有时可以方便地使用Timer安排在一个在未来的某一时刻执行的槽中来完成。在没有其他事件需要处理时,时间隔为0的定时器超时事件被相应 QSocketNotifier QNetworkAccessManager QIODevice::readyRead() 这是一个替代技术,替代有一个或多个线程在慢速网络执行阻塞读的情况。只要响应部分的计算可以快速执行,这种设计比在线程中实现的同步等待更好。与线程相比这种设计更不容易出错且更节能(energy efficient)。在许多情况下也有性能优势。 -------------------- QNetworkAccessManager: -------------------- QNetworkAccessManager m_network = new QNetworkAccessManager(this); m_cache = new QNetworkDiskCache(this); m_cache->setCacheDirectory(QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/imageanalyzer"); m_cache->setMaximumCacheSize(1000000); //set the cache to 10megs m_network->setCache(m_cache); QObject::connect(m_network, SIGNAL(finished(QNetworkReply*)),this, SLOT(handleReply(QNetworkReply*))); QNetworkRequest request = QNetworkRequest(URL); request.setRawHeader("User-Agent", "Digia - Custom Qt app"); m_network->get(request); QNetworkDiskCache=== QUrl URL = QUrl(url); QIODevice * pData = m_cache->data(URL); QImage image; image.load(pData, 0); 用webview:其中page()和setUrl()来自webview page()->setNetworkAccessManager(m_network); QUrl startURL = QUrl("qrc:/index.html"); setUrl(startURL); page()->mainFrame()->addToJavaScriptWindowObject(QString("imageAnalyzer"), m_analyzer); //为web注入数据 -------------------- C++构造函数定义: -------------------- ImageAnalyzer::ImageAnalyzer(QNetworkDiskCache* netcache, QObject* parent) : QObject(parent), m_cache(netcache), m_outstandingFetches(0){ .... } -------------------- QFuture/QFutureWatcher: -------------------- QFuture类代表了一个异步调用的结果。而这个异步调用需要使用Qt Concurrent架构中的API。 如果这个结果在调用其result(), resultAt(), 或者 results()方法时还没有准备好,QFuture将会一直等到结果准备好 可以通过setPaused(),pause(), resume(), 或者 togglePaused()来停止执行。这里需要注意不是所有的异步执行都可以取消或者停止。 例如通过QtConcurrent::run()的future是不能被取消的,而通过QtConcurrent::mappedReduced()获得的future则可以被取消。 可以通过progressValue(), progressMinimum(), progressMaximum(), and progressText()方法来获得执行的进度信息。waitForFinished()方法会导致当前线程阻塞只到异步执行结束。 异步执行的状态信息可以通过isCanceled(), isStarted(), isFinished(), isRunning(), 或者 isPaused()方法来获得。 如果想通过信号槽来跟异步调用实现交互,则要使用下面的QFutureWatcher。 QFutureWatcher是为QFuture而生的。通过QFutureWatcher我们可以通过信号槽来监视一个QFuture。 通过setFuture()方法可以开始监视一个QFuture。 QFuture的很多方法我们可以直接通过QFutureWatcher来访问,如progressValue(), progressMinimum(), progressMaximum(), progressText(), isStarted(), isFinished(), isRunning(), isCanceled(), isPaused(), waitForFinished(), result(), and resultAt(). The cancel(), setPaused(), pause(), resume(), and togglePaused(),这些方法都是以槽的形式出现的。 //构造QFutureWatcher以及连接信号槽 MyClass myObject; QFutureWatcher connect(&watcher, SIGNAL(finished()), &myObject, SLOT(handleFinished())); //开始异步调用 QFuture watcher.setFuture(future); -------------------- QStringList: -------------------- QStringList m_URLQueue; while (!m_URLQueue.isEmpty()){ QString url = m_URLQueue.takeFirst(); ... } QStringList field = str.split("\t"); QStringList::iterator it = list.begin(); while (it != list.end()) { myProcessing(*it); ++it; } -------------------- QApplication: -------------------- int main(int argc, char* argv[]) { QApplication app(argc, argv); MainWin win; win.show(); return app.exec(); } -------------------- QVBoxLayout: -------------------- mainLayout = new QVBoxLayout; mainLayout->addWidget(descriptionLabel); mainLayout->addWidget(addButton, 0, Qt::AlignCenter); setLayout(mainLayout); -------------------- QGridLayout: -------------------- QGridLayout *gLayout = new QGridLayout; layout2p1 -> setColumnStretch(0, 1); layout2p1 -> setColumnStretch(1, 2); ==>第0列与第1列之比为 1:2 gLayout->addWidget(nameLabel, 0, 0); gLayout->addWidget(nameText, 0, 1); ==>指定row,column添加widget gLayout -> addWidget(labelList ->at(2), 0, 1, 2, 1); ==>指定行列跨度 gLayout->addWidget(addressLabel, 1, 0, Qt::AlignLeft|Qt::AlignTop); gLayout->addWidget(addressText, 1, 1, Qt::AlignLeft); ==>指定对齐方式 QHBoxLayout *buttonLayout = new QHBoxLayout; buttonLayout->addWidget(okButton); buttonLayout->addWidget(cancelButton); gLayout->addLayout(buttonLayout, 2, 1, Qt::AlignRight); ==>添加其它布局 setLayout(mainLayout); ==>为主体界面设定layout -------------------- QMenu/QAction: ==>菜单管理 -------------------- extends: QMainWindow fileMenu = menuBar()->addMenu(tr("&File")); ==>添加菜单 openAct = new QAction(tr("&Open..."), this); fileMenu->addAction(openAct); connect(openAct, SIGNAL(triggered()), this, SLOT(openFile())); ==>加菜单项 toolMenu->addSeparator(); ==>菜单项分隔条 cutAct = new QAction(QIcon(":/images/cut.png"), tr("Cu&t"), this); ==>带图片菜单 removeAct->setEnabled(true);==>菜单项enable? -------------------- QWidget: -------------------- QString name = aDialog.nameText->text();==> QLineEdit QString address = aDialog.addressText->toPlainText();==> QTextEdit (1)QTabWidget: ==>extends QTabWidget addTab(newAddressTab, "Address Book"); ==>添加名为"Address Book"的tab,newAddressTab为一个widget insertTab(0, newAddressTab, "Address Book"); (2)QMessageBox: QMessageBox::information(this, tr("Duplicate Name"), tr("The name \"%1\" already exists.").arg(name)); -------------------- QTableView:==>来自address book example -------------------- //table model定义: class TableModel : public QAbstractTableModel { Q_OBJECT public: TableModel(QObject *parent = 0); TableModel(QList int rowCount(const QModelIndex &parent) const; int columnCount(const QModelIndex &parent) const; QVariant data(const QModelIndex &index, int role) const; QVariant headerData(int section, Qt::Orientation orientation, int role) const; ==>定义header Qt::ItemFlags flags(const QModelIndex &index) const; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); bool insertRows(int position, int rows, const QModelIndex &index = QModelIndex()); bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex()); QList private: QList }; QVariant TableModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole) return QVariant(); if (orientation == Qt::Horizontal) { switch (section) { case 0: return tr("Name"); case 1: return tr("Address"); default: return QVariant(); } } return QVariant(); } QVariant TableModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); if (index.row() >= listOfPairs.size() || index.row() < 0) return QVariant(); if (role == Qt::DisplayRole) { QPair if (index.column() == 0) return pair.first; else if (index.column() == 1) return pair.second; } return QVariant(); } bool TableModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (index.isValid() && role == Qt::EditRole) { int row = index.row(); QPair if (index.column() == 0) p.first = value.toString(); else if (index.column() == 1) p.second = value.toString(); else return false; listOfPairs.replace(row, p); emit(dataChanged(index, index)); return true; } return false; } bool TableModel::insertRows(int position, int rows, const QModelIndex &index) { Q_UNUSED(index); beginInsertRows(QModelIndex(), position, position + rows - 1);==>** for (int row = 0; row < rows; ++row) { QPair listOfPairs.insert(position, pair); } endInsertRows();==>** return true; } bool TableModel::removeRows(int position, int rows, const QModelIndex &index) { Q_UNUSED(index); beginRemoveRows(QModelIndex(), position, position + rows - 1);==>** for (int row = 0; row < rows; ++row) { listOfPairs.removeAt(position); } endRemoveRows();==>** return true; } //table view创建: proxyModel = new QSortFilterProxyModel(this); proxyModel->setSourceModel(table);//data model QTableView *tableView = new QTableView; tableView->setModel(proxyModel); tableView->setSortingEnabled(true);//是否可排序,在header部分点击排序 tableView->setSelectionBehavior(QAbstractItemView::SelectRows);//选择模式,行选还单元格选 tableView->horizontalHeader()->setStretchLastSection(true);//最后一个column是否拉伸到全部空间 tableView->verticalHeader()->hide();//竖标题栏是否显示 tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);//编辑模式触发方式 tableView->setSelectionMode(QAbstractItemView::SingleSelection);//单选还是多选 tableView->setColumnWidth(0, 60);//列宽? QString newStr = QString("^[%1].*").arg(str); proxyModel->setFilterRegExp(QRegExp(newStr, Qt::CaseInsensitive));//过滤器 proxyModel->setFilterKeyColumn(0);//执行过滤的行 proxyModel->sort(0, Qt::AscendingOrder);//默认排序 //data model操作: table->insertRows(0, 1, QModelIndex()); ==>插入一行 QModelIndex index = table->index(0, 0, QModelIndex()); ==>表格单无描述符QModelIndex //remove entry: QTableView *temp = static_cast QSortFilterProxyModel *proxy = static_cast QItemSelectionModel *selectionModel = temp->selectionModel(); QModelIndexList indexes = selectionModel->selectedRows(); foreach (QModelIndex index, indexes) { int row = proxy->mapToSource(index).row(); ==>对应到原始行 table->removeRows(row, 1, QModelIndex()); ==> table为tableview之model } -------------------- QTableView之另一类用法: -------------------- QTableView常用于实现数据的表格显示。下面我们如何按步骤实现学生信息表格: 一 添加表头 //准备数据模型 QStandardItemModel *student_model = new QStandardItemModel(); student_model->setHorizontalHeaderItem(0, new QStandardItem(QObject::tr("Name"))); student_model->setHorizontalHeaderItem(1, new QStandardItem(QObject::tr("NO."))); //利用setModel()方法将数据模型与QTableView绑定 ui->student_tableview->setModel(student_model); 二 设置表格属性 //设置列宽不可变动,即不能通过鼠标拖动增加列宽 ui->student_tableview->horizontalHeader()->setResizeMode(0, QHeaderView::Fixed); ui->student_tableview->horizontalHeader()->setResizeMode(1, QHeaderView::Fixed); //设置表格的各列的宽度值 ui->student_tableview->setColumnWidth(0,100); ui->student_tableview->setColumnWidth(1,100); //默认显示行头,如果你觉得不美观的话,我们可以将隐藏 ui->student_tableview->verticalHeader()->hide(); //设置选中时为整行选中 ui->student_tableview->setSelectionBehavior(QAbstractItemView::SelectRows); //设置表格的单元为只读属性,即不能编辑 ui->student_tableview->setEditTriggers(QAbstractItemView::NoEditTriggers); //如果你用在QTableView中使用右键菜单,需启用该属性 ui->tstudent_tableview->setContextMenuPolicy(Qt::CustomContextMenu); 三 动态添加行 在表格中添加行时,我们只需要在model中插入数据即可,一旦model中的数据发生变化,QTabelView显示就会做相应的变动 //在第一行添加学生张三的个人信息(setItem函数的第一个参数表示行号,第二个表示列号,第三个为要显示的数据) student_model->setItem(0, 0, new QStandardItem(“张三")); student_model->setItem(0, 1, new QStandardItem("20120202")); 四 设置数据显示的样式 //设置单元格文本居中,张三的数据设置为居中显示 student_model->item(0, 0)->setTextAlignment(Qt::AlignCenter); student_model->item(0, 1)->setTextAlignment(Qt::AlignCenter); //设置单元格文本颜色,张三的数据设置为红色 student_model->item(0, 0)->setForeground(QBrush(QColor(255, 0, 0))); student_model->item(0, 1)->setForeground(QBrush(QColor(255, 0, 0))); -------------------- Tree之QFileSystemModel/TreeModel(from file): -------------------- QFileSystemModel model; model.setRootPath(""); QTreeView tree; tree.setModel(&model); // Demonstrating look and feel features tree.setAnimated(false);==>展开/关闭时动画效果 tree.setIndentation(20);==>父子结点缩进 tree.setSortingEnabled(true); tree.setWindowTitle(QObject::tr("Dir View")); tree.resize(640, 480); tree.show(); QFile file(":/default.txt"); file.open(QIODevice::ReadOnly); TreeModel model(file.readAll()); file.close(); -------------------- Tree/TreeModel(from file): ==>来自editable tree model example -------------------- view = new QTreeView(centralwidget); view->setObjectName(QStringLiteral("view")); view->setAlternatingRowColors(true); view->setSelectionBehavior(QAbstractItemView::SelectItems); view->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); view->setAnimated(false); view->setAllColumnsShowFocus(true); QStringList headers; headers << tr("Title") << tr("Description"); QFile file(":/default.txt"); file.open(QIODevice::ReadOnly); TreeModel *model = new TreeModel(headers, file.readAll()); file.close(); view->setModel(model); for (int column = 0; column < model->columnCount(); ++column) view->resizeColumnToContents(column); ==>根据列宽修正 //tree model定义: class TreeModel : public QAbstractItemModel { Q_OBJECT public: TreeModel(const QStringList &headers, const QString &data, QObject *parent = 0); ~TreeModel(); QVariant data(const QModelIndex &index, int role) const; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; QModelIndex parent(const QModelIndex &index) const; int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; Qt::ItemFlags flags(const QModelIndex &index) const; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role = Qt::EditRole); bool insertColumns(int position, int columns, const QModelIndex &parent = QModelIndex()); bool removeColumns(int position, int columns, const QModelIndex &parent = QModelIndex()); bool insertRows(int position, int rows, const QModelIndex &parent = QModelIndex()); bool removeRows(int position, int rows, const QModelIndex &parent = QModelIndex()); private: void setupModelData(const QStringList &lines, TreeItem *parent); TreeItem *getItem(const QModelIndex &index) const; TreeItem *rootItem;==>内部存储结构,用TreeItem来表示 }; //由以上可知,tree model和table model一样,只关注通用、抽象层面的接口 而这些抽象通用的接口主要通过以下类/方法来描述: QVariant、QModelIndex,然后是一些回调方法,至于这些怎么实现,框架一概不关注. //tree model实现: TreeModel::TreeModel(const QStringList &headers, const QString &data, QObject *parent) : QAbstractItemModel(parent) { QVector foreach (QString header, headers) rootData << header; rootItem = new TreeItem(rootData); setupModelData(data.split(QString("\n")), rootItem); } int TreeModel::columnCount(const QModelIndex & /* parent */) const { return rootItem->columnCount(); } QVariant TreeModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); if (role != Qt::DisplayRole && role != Qt::EditRole) return QVariant(); TreeItem *item = getItem(index); return item->data(index.column()); } Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const { if (!index.isValid()) return 0; return Qt::ItemIsEditable | QAbstractItemModel::flags(index); } TreeItem *TreeModel::getItem(const QModelIndex &index) const { if (index.isValid()) { TreeItem *item = static_cast if (item) return item; } return rootItem; } QVariant TreeModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) return rootItem->data(section); return QVariant(); } QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) const { if (parent.isValid() && parent.column() != 0) return QModelIndex(); TreeItem *parentItem = getItem(parent); TreeItem *childItem = parentItem->child(row); if (childItem) return createIndex(row, column, childItem); else return QModelIndex(); } bool TreeModel::insertColumns(int position, int columns, const QModelIndex &parent) { bool success; beginInsertColumns(parent, position, position + columns - 1); success = rootItem->insertColumns(position, columns); endInsertColumns(); return success; } bool TreeModel::insertRows(int position, int rows, const QModelIndex &parent) { TreeItem *parentItem = getItem(parent); bool success; beginInsertRows(parent, position, position + rows - 1); success = parentItem->insertChildren(position, rows, rootItem->columnCount()); endInsertRows(); return success; } QModelIndex TreeModel::parent(const QModelIndex &index) const { if (!index.isValid()) return QModelIndex(); TreeItem *childItem = getItem(index); TreeItem *parentItem = childItem->parent(); if (parentItem == rootItem) return QModelIndex(); return createIndex(parentItem->childNumber(), 0, parentItem); } bool TreeModel::removeColumns(int position, int columns, const QModelIndex &parent) { bool success; beginRemoveColumns(parent, position, position + columns - 1); success = rootItem->removeColumns(position, columns); endRemoveColumns(); if (rootItem->columnCount() == 0) removeRows(0, rowCount()); return success; } bool TreeModel::removeRows(int position, int rows, const QModelIndex &parent) { TreeItem *parentItem = getItem(parent); bool success = true; beginRemoveRows(parent, position, position + rows - 1); success = parentItem->removeChildren(position, rows); endRemoveRows(); return success; } int TreeModel::rowCount(const QModelIndex &parent) const { TreeItem *parentItem = getItem(parent); return parentItem->childCount(); } bool TreeModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (role != Qt::EditRole) return false; TreeItem *item = getItem(index); bool result = item->setData(index.column(), value); if (result) emit dataChanged(index, index); return result; } bool TreeModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role) { if (role != Qt::EditRole || orientation != Qt::Horizontal) return false; bool result = rootItem->setData(section, value); if (result) emit headerDataChanged(orientation, section, section); return result; } void TreeModel::setupModelData(const QStringList &lines, TreeItem *parent) { QList QList parents << parent; indentations << 0; int number = 0; while (number < lines.count()) { int position = 0; while (position < lines[number].length()) { if (lines[number].mid(position, 1) != " ") break; ++position; } QString lineData = lines[number].mid(position).trimmed(); if (!lineData.isEmpty()) { // Read the column data from the rest of the line. QStringList columnStrings = lineData.split("\t", QString::SkipEmptyParts); QVector for (int column = 0; column < columnStrings.count(); ++column) columnData << columnStrings[column]; if (position > indentations.last()) { // The last child of the current parent is now the new parent // unless the current parent has no children. if (parents.last()->childCount() > 0) { parents << parents.last()->child(parents.last()->childCount()-1); indentations << position; } } else { while (position < indentations.last() && parents.count() > 0) { parents.pop_back(); indentations.pop_back(); } } // Append a new item to the current parent's list of children. TreeItem *parent = parents.last(); parent->insertChildren(parent->childCount(), 1, rootItem->columnCount()); for (int column = 0; column < columnData.size(); ++column) parent->child(parent->childCount() - 1)->setData(column, columnData[column]); } ++number; } } //tree item定义: class TreeItem { public: explicit TreeItem(const QVector ~TreeItem(); TreeItem *child(int number); int childCount() const; int columnCount() const; QVariant data(int column) const; bool insertChildren(int position, int count, int columns); bool insertColumns(int position, int columns); TreeItem *parent(); bool removeChildren(int position, int count); bool removeColumns(int position, int columns); int childNumber() const; bool setData(int column, const QVariant &value); private: QList QVector TreeItem *parentItem; }; TreeItem *TreeItem::child(int number) { return childItems.value(number); } int TreeItem::childCount() const { return childItems.count(); } int TreeItem::childNumber() const { if (parentItem) return parentItem->childItems.indexOf(const_cast return 0; } QVariant TreeItem::data(int column) const { return itemData.value(column); } bool TreeItem::insertChildren(int position, int count, int columns) { if (position < 0 || position > childItems.size()) return false; for (int row = 0; row < count; ++row) { QVector TreeItem *item = new TreeItem(data, this); childItems.insert(position, item); } return true; } bool TreeItem::insertColumns(int position, int columns) { if (position < 0 || position > itemData.size()) return false; for (int column = 0; column < columns; ++column) itemData.insert(position, QVariant()); foreach (TreeItem *child, childItems) child->insertColumns(position, columns); return true; } TreeItem *TreeItem::parent() { return parentItem; } bool TreeItem::removeChildren(int position, int count) { if (position < 0 || position + count > childItems.size()) return false; for (int row = 0; row < count; ++row) delete childItems.takeAt(position); return true; } bool TreeItem::removeColumns(int position, int columns) { if (position < 0 || position + columns > itemData.size()) return false; for (int column = 0; column < columns; ++column) itemData.remove(position); foreach (TreeItem *child, childItems) child->removeColumns(position, columns); return true; } bool TreeItem::setData(int column, const QVariant &value) { if (column < 0 || column >= itemData.size()) return false; itemData[column] = value; return true; } -------------------- QDialog: ==>动态显示对话框 -------------------- AddDialog aDialog; if (aDialog.exec()) { QString name = aDialog.nameText->text(); QString address = aDialog.addressText->toPlainText(); emit sendDetails(name, address); } -------------------- Qt与html/javascript互调: -------------------- 暴露c++接口给javascript: page()->mainFrame()->addToJavaScriptWindowObject(QString("imageAnalyzer"), m_analyzer); //为web注入数据 javascript中调被暴露的接口: imageAnalyzer.startAnalysis(stringlist); javascript中signal/slot机制: imageAnalyzer.finishedAnalysis.connect(this, finished); imageAnalyzer.updateProgress.connect(this, updateProg); demo project: webkit bridge tutorial -------------------- QRegExp正则表达式: -------------------- (1)提取: http://qt-project.org/doc/qt-4.8/qregexp.html QRegExp rx("(\\d+)"); QString str = "Offsets: 12 14 99 231 7"; QStringList list; int pos = 0; while ((pos = rx.indexIn(str, pos)) != -1) { list << rx.cap(1); pos += rx.matchedLength(); } (2)测试: QRegExp rx("*.txt"); rx.setPatternSyntax(QRegExp::Wildcard);//Wildcard Matching,unix文件名通配 rx.exactMatch("README.txt"); // returns true rx.exactMatch("welcome.txt.bak"); // returns false (3)替换: QRegExp rx("&(?!amp;)"); // match ampersands but not & QString line1 = "This & that"; line1.replace(rx, "&"); // line1 == "This & that" QString line2 = "His & hers & theirs"; line2.replace(rx, "&"); // line2 == "His & hers & theirs" (4)提取所有: QRegExp rx("(\\d+)(\\s*)(cm|inch(es)?)"); int pos = rx.indexIn("Length: 36 inches"); QStringList list = rx.capturedTexts(); (5)正则表达式语法: QRegExp::RegExp0A rich Perl-like pattern matching syntax. This is the default. QRegExp::RegExp23Like RegExp, but with greedy quantifiers. This will be the default in Qt 5. (Introduced in Qt 4.2.) QRegExp::Wildcard1This provides a simple pattern matching syntax similar to that used by shells (command interpreters) for "file globbing". See Wildcard Matching. QRegExp::WildcardUnix4This is similar to Wildcard but with the behavior of a Unix shell. The wildcard characters can be escaped with the character "\". QRegExp::FixedString2The pattern is a fixed string. This is equivalent to using the RegExp pattern on a string in which all metacharacters are escaped using escape(). QRegExp::W3CXmlSchema115The pattern is a regular expression as defined by the W3C XML Schema 1.1 specification. -------------------- static_cast、dynamic_cast、reinterpret_cast和const_cast: -------------------- (1)static_cast: ==> static_cast < type-id > ( expression ) 该运算符把expression转换为type-id类型,但没有运行时类型检查来保证转换的安全性。 ①用于类层次结构中基类和子类之间指针或引用的转换。 ②用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。 ③把空指针转换成目标类型的空指针。 ④把任何类型的表达式转换成void类型。 int n=9; double d=static_cast < double > (n); 上面的例子中, 我们将一个变量从 int 转换到 double。 这些类型的二进制表达式是不同的。 要将整数 9 转换到 双精度整数 (2)dynamic_cast: ==> dynamic_cast < type-id > ( expression ) 该运算符把expression转换成type-id类型的对象。Type-id必须是类的指针、类的引用或者void *; 在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的; 在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。 另外,dynamic_cast还支持交叉转换(cross cast)。如下代码所示。 class A{ public: int m_iNum; virtual void f(){} }; class B:public A{ }; class D:public A{ }; void foo(){ B *pb = new B; pb->m_iNum = 100; D *pd1 = static_cast D *pd2 = dynamic_cast delete pb; } (3)reinterpret_cast: ==> reinterpret_cast type-id必须是一个指针、引用、算术类型、函数指针或者成员指针。 它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数, 在把该整数转换成原类型的指针,还可以得到原先的指针值)。 int n=9;double d=reinterpret_cast 这次, 结果有所不同. 在进行计算以后, d 包含无用值. 这是因为 reinterpret_cast 仅仅是复制 n 的比特位到 d, 没有进行必要的分析. (4)const_cast: ==> const_cast 该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外, type_id和expression的类型是一样的。 常量指针被转化成非常量指针,并且仍然指向原来的对象; 常量引用被转换成非常量引用,并且仍然指向原来的对象;常量对象被转换成非常量对象。 -------------------- Qt Container:容器类 -------------------- template template template template template template template template template template template template template -------------------- Qt资源管理: -------------------- Q_INIT_RESOURCE(editabletreemodel); //强制资源加载,必须存在有名为editabletreemodel.qrc的资源文件 QFile file(":/default.txt");==>访问资源文件 (1)Compiled-In Resources:编译进二进制文件 必须在应用程序的 .pro 文件中指定.qrc 文件, qmake 才能知道并将资源编译进二进制文件。例如: RESOURCES=application.qrc (2)外部资源: rcc -binary myresource.qrc -o myresource.rcc ==>创建外部资源 QResource::registerResource("/path/to/myresource.rcc");