Qt学习略记

-----------------------------------

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 * m_watcher;

--------------------

QList:

--------------------

QList m_imageQueue = 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 watcher;

connect(&watcher, SIGNAL(finished()), &myObject, SLOT(handleFinished()));

 

//开始异步调用

QFuture future = QtConcurrent::run(...);

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 > listofPairs, QObject *parent = 0);

    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 > getList();

 

private:

    QList > listOfPairs;  ==>用来存储table数据

};

 

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 pair = listOfPairs.at(index.row());

        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 p = listOfPairs.value(row);

        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 pair(" ", " ");

        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(currentWidget());   ==> 当前widget继承自QTableView

QSortFilterProxyModel *proxy = static_cast(temp->model());

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 rootData;

    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(index.internalPointer());

        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 parents;

    QList indentations;

    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 columnData;

            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 &data, TreeItem *parent = 0);

    ~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 childItems;

    QVector itemData;

    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(this));

 

    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 data(columns);

        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(pb);    //compile error

    D *pd2 = dynamic_cast(pb); //pd2 is NULL

    delete pb;

}

 

(3)reinterpret_cast: ==> reinterpret_cast (expression)

type-id必须是一个指针、引用、算术类型、函数指针或者成员指针。

它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,

在把该整数转换成原类型的指针,还可以得到原先的指针值)。

int n=9;double d=reinterpret_cast (n);

这次, 结果有所不同. 在进行计算以后, d 包含无用值. 这是因为 reinterpret_cast 仅仅是复制 n 的比特位到 d, 没有进行必要的分析. 

 

(4)const_cast:  ==> const_cast (expression)

该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外, type_id和expression的类型是一样的。

常量指针被转化成非常量指针,并且仍然指向原来的对象;

常量引用被转换成非常量引用,并且仍然指向原来的对象;常量对象被转换成非常量对象。

--------------------

Qt Container:容器类

--------------------

template class QCache;

template class QHash;

template class QLinkedList;

template class QList;

template class QMap;

template class QMultiHash;

template class QMultiMap;

template struct QPair;

template class QQueue;

template class QSet;

template class QStack;

template class QVarLengthArray;

template class QVector;

--------------------

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");

你可能感兴趣的:(C++,qt,C++,Qt)