精华内容
下载资源
问答
  • Qt 实现甘特图

    2021-01-12 14:05:40
    做项目遇到要写一个甘特图的功能,而且还要能拖拽的功能。。
  • qt实现甘特图源码

    热门讨论 2013-07-29 20:58:08
    源码中含有使用QT实现甘特图的控件
  • Qt4 实现甘特图效果

    2018-07-25 20:37:02
    自定义QAbstractItemView实现甘特图效果,本工程内的代码可参考Qt4的chart例子代码
  • Qt甘特图控件

    千次阅读 2018-07-25 21:06:00
    本文介绍了如何在Qt4中自定义View控件实现甘特图效果。

    本片博客中代码仅使用于Qt4,Qt5中已经提供了QChart类无需在造轮子实现类似效果。

    在这片博客中,我将详细讲述如何是通过QAbstractItemView定制一个GanttView。本篇博文中的代码参考自Qt4例子chart,有兴趣的同学可以查看chart代码深入理解如何定制自己的view控件。(注:在写这篇博客的代码时犯了懒癌,不想写注释……)

    详细代码

    MainWindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include <QSplitter>
    #include <QTableView>
    #include "GanttView.h"
    #include <QStandardItemModel>
    #include <QTableView>
    
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
    
    private:
        void initModel();
        void initView();
    
    private:
        Ui::MainWindow *ui;
    
        QSplitter *_splitter;
        QAbstractItemModel *_model;
        QTableView *_table;
        GanttView *_ganttView;
        QItemSelectionModel *_selectionModel;
    };
    
    #endif // MAINWINDOW_H
    

    MainWindow.cpp

    #include "MainWindow.h"
    #include "ui_MainWindow.h"
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        initModel();
        initView();
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    void MainWindow::initModel()
    {
        _model = new QStandardItemModel(5,3,this);
        _model->setHeaderData(0,Qt::Horizontal,QString("event"));
        _model->setHeaderData(1,Qt::Horizontal,QString("StartDate"));
        _model->setHeaderData(2,Qt::Horizontal,QString("EndDate"));
    
        QDate startDate = QDate::currentDate();
        for (int row = 0; row < _model->rowCount(); ++row)
        {
            _model->setData(_model->index(row,0),QString::number(row+1));
            _model->setData(_model->index(row,1),startDate.addDays(row));
            _model->setData(_model->index(row,2),startDate.addDays(row+5));
        }
    }
    
    void MainWindow::initView()
    {
        _splitter = new QSplitter;
    
        _table = new QTableView;
        _table->setModel(_model);
        _table->setSelectionMode(QAbstractItemView::SingleSelection);
        _table->setSelectionBehavior(QAbstractItemView::SelectRows);
        _table->horizontalHeader()->setStretchLastSection(true);
        _table->horizontalHeader()->setDefaultSectionSize(100);
        _table->horizontalHeader()->setMinimumWidth(100);
        _table->verticalHeader()->setVisible(false);
    
        _ganttView = new GanttView;
        _ganttView->setModel(_model);
    
        QItemSelectionModel *selectionModel = new QItemSelectionModel(_model);
        _table->setSelectionModel(selectionModel);
        _ganttView->setSelectionModel(selectionModel);
    
        _splitter->addWidget(_table);
        _splitter->addWidget(_ganttView);
    
        _splitter->setStretchFactor(0, 2);
        _splitter->setStretchFactor(1, 3);
    
        setCentralWidget(_splitter);
    }
    

    GanttView.h

    #ifndef GanttView_H
    #define GanttView_H
    
    #include <QAbstractItemView>
    #include <QFont>
    #include <QItemSelection>
    #include <QItemSelectionModel>
    #include <QStandardItemModel>
    #include <QModelIndex>
    #include <QRect>
    #include <QSize>
    #include <QPoint>
    #include <QWidget>
    #include <QDate>
    
    class GanttView : public QAbstractItemView
    {
        Q_OBJECT
    public:
        explicit GanttView(QWidget *parent = 0);
        ~GanttView(void);
    
        QRect visualRect(const QModelIndex &index) const;
        void scrollTo(const QModelIndex &, ScrollHint = EnsureVisible);
        QModelIndex indexAt(const QPoint &point) const;
    
    protected slots:
        void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
        void rowsInserted(const QModelIndex &parent, int start, int end);
        void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
    
    signals:
        void sgCurrentSerialNumberChanged(const int sn) const;
    
    protected:
        bool edit(const QModelIndex &index, EditTrigger trigger, QEvent *event);
        QModelIndex moveCursor(QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers);
    
        int horizontalOffset() const;
        int verticalOffset() const;
    
        bool isIndexHidden(const QModelIndex &) const;
    
        void setSelection(const QRect&, QItemSelectionModel::SelectionFlags command);
    
        void mousePressEvent(QMouseEvent *event);
    
        void mouseMoveEvent(QMouseEvent *event);
        void mouseReleaseEvent(QMouseEvent *event);
    
        void paintEvent(QPaintEvent *event);
        void resizeEvent(QResizeEvent *);
        void scrollContentsBy(int dx, int dy);
    
        QRegion visualRegionForSelection(const QItemSelection &selection) const;
    
    private:
        QRect itemRect(const QModelIndex &item) const;
        QRegion itemRegion(const QModelIndex &index) const;
        int rows(const QModelIndex &index = QModelIndex()) const;
        void updateGeometries();
        void updateMetaData();
    
    private:
        int _rectHeight;
        int _space;
        int _lengthX;
        int _lengthY;
        QPoint _origin;
        QRubberBand *_rubberBand;
    
        QDate _startDate;
        int _pixPerDay;
    
    };
    
    #endif // GanttView_H
    

    GanttView.cpp

    #include "GanttView.h"
    #include <QtGui>
    #include <QDate>
    
    GanttView::GanttView(QWidget *parent) : QAbstractItemView(parent)
    {
        horizontalScrollBar()->setRange(0, 0);
        verticalScrollBar()->setRange(0, 0);
    
        _rubberBand = 0;
        _rectHeight = 20;
        _space = 0;
        _pixPerDay = 10;
        _lengthX = 100;
        _lengthY = 100;
    
        setEditTriggers(QAbstractItemView::NoEditTriggers);
    }
    
    GanttView::~GanttView()
    {}
    
    QRect GanttView::visualRect(const QModelIndex &index) const
    {
        QRect rect = itemRect(index);
        if (rect.isValid())
            return QRect(rect.left() - horizontalScrollBar()->value(), rect.top() - verticalScrollBar()->value(), rect.width(), rect.height());
        else
            return rect;
    }
    
    void GanttView::scrollTo(const QModelIndex &/*index*/, QAbstractItemView::ScrollHint /*hint*/)
    {
        update();
    }
    
    QModelIndex GanttView::indexAt(const QPoint &point) const
    {
        int wx = point.x() + horizontalScrollBar()->value();
        int wy = point.y() + verticalScrollBar()->value();
    
        double cx = wx - 50;
        double cy = wy - 50;
    
        for (int row = 0; row < model()->rowCount(rootIndex()); ++row)
        {
            QDate currentStartDate = model()->data(model()->index(row,1)).toDate();
            QDate currentEndDate = model()->data(model()->index(row,2)).toDate();
    
            QPoint lt = QPoint(_startDate.daysTo(currentStartDate)*_pixPerDay,(_rectHeight+_space)*row);
            QPoint rd = QPoint(_startDate.daysTo(currentEndDate)*_pixPerDay,(_rectHeight+_space)*row+_rectHeight);
    
            if (cx>lt.x()&&cy>lt.y()&&cx<rd.x()&&cy<rd.y())
            {
                return model()->index(row, 0, rootIndex());
            }
        }
    
        return QModelIndex();
    }
    
    void GanttView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
    {
        QAbstractItemView::dataChanged(topLeft, bottomRight);
        updateMetaData();
        viewport()->update();
    }
    
    void GanttView::rowsInserted(const QModelIndex &parent, int start, int end)
    {
        QAbstractItemView::rowsInserted(parent, start, end);
    }
    
    void GanttView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
    {
        QAbstractItemView::rowsAboutToBeRemoved(parent, start, end);
    }
    
    bool GanttView::edit(const QModelIndex &index, QAbstractItemView::EditTrigger trigger, QEvent *event)
    {
        if (index.column() == 0)
            return QAbstractItemView::edit(index, trigger, event);
        else
            return false;
    }
    
    QModelIndex GanttView::moveCursor(QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
    {
        QModelIndex current = currentIndex();
        if (model() == NULL) return current;
    
        switch (cursorAction) {
        case MoveLeft:
        case MoveUp:
            if (current.row() > 0)
                current = model()->index(current.row() - 1, current.column(), rootIndex());
            else
                current = model()->index(0, current.column(), rootIndex());
            break;
        case MoveRight:
        case MoveDown:
            if (current.row() < rows(current) - 1)
                current = model()->index(current.row() + 1, current.column(), rootIndex());
            else
                current = model()->index(rows(current) - 1, current.column(), rootIndex());
            break;
        default:
            break;
        }
    
        viewport()->update();
        return current;
    }
    
    int GanttView::horizontalOffset() const
    {
        return horizontalScrollBar()->value();
    }
    
    int GanttView::verticalOffset() const
    {
        return verticalScrollBar()->value();
    }
    
    bool GanttView::isIndexHidden(const QModelIndex &/*index*/) const
    {
        return false;
    }
    
    void GanttView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command)
    {
        // Use content widget coordinates because we will use the itemRegion()
        // function to check for intersections.
        if (model() == NULL) return;
    
        QRect contentsRect = rect.translated( horizontalScrollBar()->value(), verticalScrollBar()->value()).normalized();
    
        int rows = model()->rowCount(rootIndex());
        QModelIndexList indexes;
    
        for (int row = 0; row < rows; ++row)
        {
            QModelIndex index = model()->index(row, 0, rootIndex());
            QRegion region = itemRegion(index);
            if (!region.intersect(contentsRect).isEmpty())
                indexes.append(index);
        }
    
        if (indexes.size() > 0)
        {
            int firstRow = indexes[0].row();
            int lastRow = indexes[0].row();
            int firstColumn = indexes[0].column();
            int lastColumn = indexes[0].column();
    
            for (int i = 0; i < indexes.size(); ++i)
            {
                firstRow = qMin(firstRow, indexes[i].row());
                lastRow = qMax(lastRow, indexes[i].row());
                firstColumn = qMin(firstColumn, indexes[i].column());
                lastColumn = qMax(lastColumn, indexes[i].column());
            }
    
            QItemSelection selection( model()->index(firstRow, firstColumn, rootIndex()), model()->index(lastRow, lastColumn, rootIndex()));
            selectionModel()->select(selection, command);
        }
        else
        {
            QModelIndex noIndex;
            QItemSelection selection(noIndex, noIndex);
            selectionModel()->select(selection, command);
        }
    
        update();
    }
    
    void GanttView::mousePressEvent(QMouseEvent *event)
    {
        QAbstractItemView::mousePressEvent(event);
        _origin = event->pos();
        if (!_rubberBand)
            _rubberBand = new QRubberBand(QRubberBand::Rectangle, viewport());
        _rubberBand->setGeometry(QRect(_origin, QSize()));
        _rubberBand->show();
    }
    
    void GanttView::mouseMoveEvent(QMouseEvent *event)
    {
        if (_rubberBand)
            _rubberBand->setGeometry(QRect(_origin, event->pos()).normalized());
        QAbstractItemView::mouseMoveEvent(event);
    }
    
    void GanttView::mouseReleaseEvent(QMouseEvent *event)
    {
        QAbstractItemView::mouseReleaseEvent(event);
        if (_rubberBand)
            _rubberBand->hide();
        viewport()->update();
    }
    
    void GanttView::paintEvent(QPaintEvent *event)
    {
        if (model() == NULL) return;
    
        QItemSelectionModel *selections = selectionModel();
        QStyleOptionViewItem option = viewOptions();
    
        QBrush background = option.palette.base();
        QPen foreground(option.palette.color(QPalette::WindowText));
    
        QPainter painter(viewport());
        painter.setRenderHint(QPainter::Antialiasing);
    
        painter.fillRect(event->rect(), background);
        painter.setPen(foreground);
    
        painter.save();
        painter.translate(50 - horizontalScrollBar()->value(),50-verticalScrollBar()->value());
        painter.drawLine(0,0,0,_lengthY);
        painter.drawLine(0,0,_lengthX,0);
        painter.drawText(-6,_lengthY+13,QString("sn"));
        painter.drawText(_lengthX+3,3,QString("day"));
    
        ///画Y轴箭头
        painter.translate(0,_lengthY);
        painter.drawLine(1,1,6,-8);
        painter.drawLine(-1,1,-6,-8);
    
        ///画X轴箭头
        painter.translate(_lengthX,-_lengthY);
        painter.drawLine(-1,-1,-8,-6);
        painter.drawLine(-1,1,-8,6);
    
        painter.translate(-_lengthX,0);
    
        /// 画X轴刻度
        for (int i = 0; i < _lengthX; i+=50)
        {
            painter.drawLine(i,0,i,5);
            painter.drawText(i - 7,-5,QString::number(i/10));
        }
    
        /// 画Y轴刻度
        for (int i = 1; i < model()->rowCount()+1; ++i)
        {
            painter.drawLine(0,(_rectHeight+_space)*i,5,(_rectHeight+_space)*i);
            painter.drawText(-15,(_rectHeight+_space)*i - 10,QString::number(i));
        }
    
        for (int row = 0; row < model()->rowCount(); ++row)
        {
            QDate startDate = model()->data(model()->index(row,1)).toDate();
            QDate endDate = model()->data(model()->index(row,2)).toDate();
            int duration = startDate.daysTo(endDate);
    
            QModelIndex index = model()->index(row, 0);
    
            if (currentIndex() == index && selections->isSelected(index))
                painter.setBrush(QBrush(QColor::fromHsvF(qreal(row)/qreal(model()->rowCount()),1.0,1.0), Qt::Dense4Pattern));
            else
                painter.setBrush(QBrush(QColor::fromHsvF(qreal(row)/qreal(model()->rowCount()),1.0,1.0)));
    
            painter.drawRect(_startDate.daysTo(startDate)*_pixPerDay,(_rectHeight+_space)*(row),duration*_pixPerDay,_rectHeight);
        }
        painter.restore();
    }
    
    void GanttView::resizeEvent(QResizeEvent */*event*/)
    {
        updateGeometries();
    }
    
    void GanttView::scrollContentsBy(int dx, int dy)
    {
        viewport()->scroll(dx, dy);
    }
    
    QRegion GanttView::visualRegionForSelection(const QItemSelection &selection) const
    {
        if (model() == NULL) return QRect();;
        int ranges = selection.count();
    
        if (ranges == 0)
            return QRect();
    
        QRegion region;
        for (int i = 0; i < ranges; ++i) {
            QItemSelectionRange range = selection.at(i);
            for (int row = range.top(); row <= range.bottom(); ++row) {
                for (int col = range.left(); col <= range.right(); ++col) {
                    QModelIndex index = model()->index(row, col, rootIndex());
                    region += visualRect(index);
                }
            }
        }
        return region;
    }
    
    QRect GanttView::itemRect(const QModelIndex &index) const
    {
        if (model() == NULL) return QRect();
    
        if (!index.isValid())
            return QRect();
    
        if (index.column() == 0)
        {
            return viewport()->rect();
        }
    
        return QRect();
    }
    
    QRegion GanttView::itemRegion(const QModelIndex &index) const
    {
        if (!index.isValid())
            return QRegion();
    
        if (index.column() != 0)
            return itemRect(index);
    
        for (int row = 0; row < model()->rowCount(rootIndex()); ++row)
        {
            QModelIndex sliceIndex = model()->index(row, 0, rootIndex());
    
            QDate currentStartDate = model()->data(model()->index(row,1)).toDate();
            QDate currentEndDate = model()->data(model()->index(row,2)).toDate();
            int duration = currentStartDate.daysTo(currentEndDate)*_pixPerDay;
    
            if (sliceIndex == index)
            {
                QPainterPath path;
                path.addRect(_startDate.daysTo(currentStartDate)*_pixPerDay+50,(_rectHeight+_space)*row+50,duration,_rectHeight);
                return QRegion(path.toFillPolygon().toPolygon());
            }
        }
    
        return QRegion();
    }
    
    int GanttView::rows(const QModelIndex &index) const
    {
        return model()->rowCount(model()->parent(index));
    }
    
    void GanttView::updateGeometries()
    {
        if (NULL == model()) return;
    
        updateMetaData();
    
        horizontalScrollBar()->setPageStep(viewport()->width());
        horizontalScrollBar()->setRange(0, qMax(0, _lengthX - viewport()->width()));
        verticalScrollBar()->setPageStep(viewport()->height());
        verticalScrollBar()->setRange(0, qMax(0, _lengthY - viewport()->height()));
    }
    
    void GanttView::updateMetaData()
    {
        _lengthX = 5;
        _lengthY = (_rectHeight+_space)*(model()->rowCount()+1);
        if (model())
        {
            _startDate = model()->data(model()->index(0,1)).toDate();
    
            for (int row = 0; row < model()->rowCount(); ++row)
            {
                QDate currentStartDate = model()->data(model()->index(row,1)).toDate();
                QDate currentEndDate = model()->data(model()->index(row,2)).toDate();
                _startDate = qMin(currentStartDate,_startDate);
                _lengthX = qMax(_lengthX,_startDate.daysTo(currentEndDate));
            }
            _lengthX *=10;
            _lengthX += 50;
        }
    }
    

    效果图

    这里写图片描述

    以上就是在Qt4中自定义甘特图视图的全部内容。如有不明白的地方欢迎留言交流,若帖子中有错误的地方同样欢迎留言批评指正,在此谢过,欢迎骚扰。

    展开全文
  • Qt轮播动画实现

    2020-05-17 00:30:04
    目录Qt轮播动画实现新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一...

    Qt轮播图动画实现

    轮播图在网页上挺常见的,在Qt中可以用属性动画来实现。

    需要注意几点

    • 计算好需要移动图片的始末位置
    • 在合适的时候将要显示的图片添加到布局,并将要消失的图片移除布局
    • 动画结束时,把消失的图片删除
    • 当动画还没结束,又有新的动作时,应马上结束动画开始新动作

    看代码。
    wheelwidget.h

    #pragma once
    #include "QObject"
    
    #include <QWidget>
    #include <QButtonGroup>
    #include <QSize>
    #include <QDir>
    #include <QFileInfo>
    #include <QPropertyAnimation>
    #include <QTimer>
    #include <QDebug>
    #include <QThread>
    #include <QListWidgetItem>
    #include "ui_wheelwidget.h"
    #include "QParallelAnimationGroup"
    #include <QEasingCurve>
    
    //轮播图类,实现轮播效果
    class wheelwidget : public QWidget
    {
    	Q_OBJECT
    
    public:
    	wheelwidget(QWidget *parent = Q_NULLPTR);
    	~wheelwidget();
    public slots:
    	void addItem(QFileInfo fileinfo);
    	void puticeChanged(int row);
    
    private:
    	void startAnimation();
    	Ui::wheelwidget ui;
    	QButtonGroup* m_pButtonGroup;
    	QSize m_iconSize;
    	QParallelAnimationGroup* m_pAnimGroup;
    	int m_iDuration = 1000; //动画持续时间
    	int m_ipreRow = 0;
    	QWidget* m_pShouleDel = nullptr;
    	QEasingCurve::Type m_eEasingCurve = QEasingCurve::OutBounce;
    	QString m_PituceDirPath = u8"H:/秦时明月/";
    };
    
    
    //文件读取类
    class readPuticeFile : public QObject
    {
    	Q_OBJECT
    
    public:
    	readPuticeFile(QObject* parent = nullptr)
    		:QObject(parent)
    	{
    
    	}
    	void setDirPath(QString path) { m_DirPath = path; }
    
    signals:
    	void sigAddItem(QFileInfo fileinfo);
    	void sigOver();
    
    public slots:
    	void startRead()
    	{
    		qDebug() << QThread::currentThreadId();
    		QDir dir(u8"H:/秦时明月/");
    		auto filelist = dir.entryInfoList();
    		for (auto& file : filelist)
    		{
    			emit sigAddItem(file);
    // 			QThread::msleep(100);
    		}
    		emit sigOver();
    	}
    private:
    	QString m_DirPath;
    };
    

    wheelwidget.cpp

    #include "wheelwidget.h"
    #include <QIcon>
    #include <QMetaObject>
    #include <QMetaEnum>
    
    wheelwidget::wheelwidget(QWidget *parent)
    	: QWidget(parent),
    	m_iconSize(100, 100)
    {
    	ui.setupUi(this);
    	ui.listWidget->setIconSize(m_iconSize);
    	readPuticeFile* r = new readPuticeFile();
    	r->setDirPath(m_PituceDirPath);
    	QThread* t = new QThread();
    	r->moveToThread(t);//移到另一个线程
    	connect(t, &QThread::started, r, &readPuticeFile::startRead);
    	connect(r, &readPuticeFile::sigAddItem, this, &wheelwidget::addItem, Qt::QueuedConnection); //必须加上最后一个参数,不然崩溃
    	connect(r, &readPuticeFile::sigOver, t, &QThread::quit);
    	t->start();
    	connect(ui.listWidget, &QListWidget::currentRowChanged,
    		this, &wheelwidget::puticeChanged);
    	m_pAnimGroup = new QParallelAnimationGroup();
    	ui.spinBox->setValue(m_iDuration);
    	connect(ui.spinBox, QOverload<int>::of(&QSpinBox::valueChanged), [=](int i) {m_iDuration = i; });
    	const QMetaObject& mo = QEasingCurve::staticMetaObject;
    	QMetaEnum metaEnum = mo.enumerator(mo.indexOfEnumerator("Type"));
    	// Skip QEasingCurve::Custom
    	for (int i = 0; i < QEasingCurve::NCurveTypes - 1; ++i) {
    		QListWidgetItem* item = new QListWidgetItem;
    		item->setText(metaEnum.key(i));
    		ui.listWidget_2->addItem(item);
    	}
    	connect(ui.listWidget_2, &QListWidget::currentRowChanged, [=](int row) {m_eEasingCurve = (QEasingCurve::Type) row; });
    
    }
    
    wheelwidget::~wheelwidget()
    {
    }
    
    void wheelwidget::startAnimation()
    {
    }
    
    void wheelwidget::addItem(QFileInfo fileinfo)
    {
    	QListWidgetItem* item = new QListWidgetItem;
    	qDebug() << fileinfo.absoluteFilePath();
    	item->setIcon(QIcon(fileinfo.absoluteFilePath()));
    	item->setText(fileinfo.fileName());
    	item->setTextAlignment(Qt::AlignBottom | Qt::AlignLeft);//设置对齐方式
    	ui.listWidget->addItem(item);
    }
    
    void wheelwidget::puticeChanged(int row)
    {
    	if (m_pAnimGroup->state() == QAbstractAnimation::Running)
    	{
    		m_pAnimGroup->setCurrentTime(m_iDuration); //如果动画还在运行,立即完成
    	}
    	auto item = ui.listWidget->currentItem();
    	QString filename = item->text();
    	QPixmap pix(m_PituceDirPath + filename);
    	auto layout = ui.widget->layout();
    	QWidget* preLabel = layout->takeAt(0)->widget();	//先从布局中拿出来
    	m_pShouleDel = preLabel;
    	pix.scaled(preLabel->size(), Qt::KeepAspectRatio);
    	QLabel* nlabel = new QLabel(this);
    	nlabel->setPixmap(pix);
    
    	QPropertyAnimation *animation = new QPropertyAnimation(preLabel, "geometry");
    	animation->setDuration(m_iDuration);
    	animation->setStartValue(preLabel->geometry());
    	animation->setEasingCurve(m_eEasingCurve);
    	QPropertyAnimation* newanimation = new QPropertyAnimation(nlabel, "geometry");
    	newanimation->setDuration(m_iDuration);
    	newanimation->setEndValue(preLabel->geometry());
    	newanimation->setEasingCurve(m_eEasingCurve);
    	if (row > m_ipreRow)	//从右向左移动
    	{
    		QPoint np(0 - preLabel->width() - ui.widget->x(), preLabel->y());	//计算
    		animation->setEndValue(QRect(np, preLabel->size()));
    		QPoint nlp(preLabel->x() + preLabel->width(), preLabel->y());
    		newanimation->setStartValue(QRect(nlp, preLabel->size()));
    	}
    	else //从左向右移动
    	{
    		QPoint np(preLabel->x() + ui.widget->width(), preLabel->y());	//计算
    		animation->setEndValue(QRect(np, preLabel->size()));
    		QPoint nlp(preLabel->x() - preLabel->width(), preLabel->y());
    		newanimation->setStartValue(QRect(nlp, preLabel->size()));
    	}
    	m_ipreRow = row;
    	m_pAnimGroup->addAnimation(animation);
    	m_pAnimGroup->addAnimation(newanimation);
    	qDebug() << u8"动画数\t" << m_pAnimGroup->animationCount();
    	qDebug() << layout->count();
    	layout->addWidget(nlabel); //加入布局
    	connect(m_pAnimGroup, &QParallelAnimationGroup::finished, [=]() {
    		m_pShouleDel->deleteLater();	//删除移除了的图片
    		while (m_pAnimGroup->animationCount())
    		{
    			qDebug() << m_pAnimGroup->animationCount();
    			auto anim = dynamic_cast<QPropertyAnimation*>(m_pAnimGroup->takeAnimation(0));
    			anim->deleteLater();
    		}
    	});
    	m_pAnimGroup->start();
    }
    

    wheelwidget.ui

    <?xml version="1.0" encoding="UTF-8"?>
    <ui version="4.0">
     <class>wheelwidget</class>
     <widget class="QWidget" name="wheelwidget">
      <property name="geometry">
       <rect>
        <x>0</x>
        <y>0</y>
        <width>766</width>
        <height>578</height>
       </rect>
      </property>
      <property name="windowTitle">
       <string>wheelwidget</string>
      </property>
      <layout class="QVBoxLayout" name="verticalLayout_3" stretch="1,2">
       <item>
        <layout class="QHBoxLayout" name="horizontalLayout" stretch="5,1">
         <item>
          <widget class="QListWidget" name="listWidget">
           <property name="flow">
            <enum>QListView::LeftToRight</enum>
           </property>
          </widget>
         </item>
         <item>
          <layout class="QVBoxLayout" name="verticalLayout">
           <item>
            <widget class="QListWidget" name="listWidget_2"/>
           </item>
           <item>
            <widget class="QSpinBox" name="spinBox">
             <property name="maximum">
              <number>10000</number>
             </property>
            </widget>
           </item>
          </layout>
         </item>
        </layout>
       </item>
       <item>
        <widget class="QWidget" name="widget" native="true">
         <layout class="QVBoxLayout" name="verticalLayout_2">
          <item>
           <widget class="QLabel" name="label">
            <property name="text">
             <string>TextLabel</string>
            </property>
           </widget>
          </item>
         </layout>
        </widget>
       </item>
      </layout>
     </widget>
     <layoutdefault spacing="6" margin="11"/>
     <resources/>
     <connections/>
    </ui>
    

    以上代码在qt5.14.1 和vs2019上编译运行。

    展开全文
  • qt+libtorch+opencv调用u2net实现图像二值分割内容介绍整体流程模型转化qt安装在qt中配置libtorch环境和opencv环境插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居...

    内容介绍

    本篇文章主要介绍使用libtorch调用u2net网络并使用qt作为前端展示工具,最后打包实现在其他电脑中能正常运行全过程以及其中踩过坑,第一次写如有不足,请见谅。

    整体流程

    1. 选择训练好的模型,并通过traced_script将.pth文件转为.pt文件;
    2. 在qt中配置opencv和libtorch环境;
    3. 使用opencv对图片进行修改,使用libtorch读取模型;
    4. 在qt编写ui,实现前端相关操作,将结果展示;
    5. 使用qt内置的打包工具打包文件,然后将模型和相关依赖导入qt打包的文件夹中;

    模型转化

    import torch
    from model import U2NETP
    #print(torch.version.cuda)
    #print(torch.__version__)
    model = U2NETP(3, 1)#自己定义的网络模型
    model.load_state_dict(torch.load("xx.pth"))#保存的训练模型
    model.eval()
    example = torch.rand(1, 3, 320, 320).cuda()
    #example = torch.rand(1, 3, 320, 320).cpu()
    print(example.device)
    traced_script_module = torch.jit.trace(model.cuda(), example)
    #traced_script_module = torch.jit.trace(model.cpu(), example)
    traced_script_module.save("xx.pt")
    

    注释为转化为CPU版本代码。注意torch和cuda版本后面ibtorch版本要要一致

    qt安装

    由于官网速度下载较慢,建议使用清华源下载,这里教程很多不细说。

    在qt中配置libtorch环境和opencv环境

    1.下载opencv和libtorch相应的文件;
    2.注意配置环境变量,如下图;

    3.环境设置如下图;这里的./换成你自己文件是所在路径,不同版本的可能含有的lib文件有区别,大体一样;
    libtorch最好选择release版本的,debug版本可能回报莫名其妙的错误,这是我的血泪教训!!!!!!!还有构建设置里面shadow build最好不勾(勾了的话只是做简单项目基本没有好处),不然有可能在改了qt中ui但是构建出来的项目没有变,并且方便后面的打包,这也是教训!!!

    INCLUDEPATH+=./libtorch/include\
               ./libtorch/include/torch/csrc/api/include
       DEPENDPATH+=./libtorch/include\
               ./libtorch/include/torch/csrc/api/include
       LIBS += -L./libtorch/lib   -lc10_cuda -lc10 \#-lc10
       -lclog -lcpuinfo \
       -llibprotoc \
       -ltorch \#-ltorch -ltorch_cuda
    INCLUDEPATH+=./opencv/build/include\
                 ./opencv/build/include/opencv\
                 ./opencv/build/include/opencv2
           DEPENDPATH+=./opencv/build/include\
                       ./opencv/build/include/opencv\
                       ./opencv/build/include/opencv2
           LIBS += -L./opencv/build/x64/vc15/lib \
               -lopencv_world3414d \
               -lopencv_world3414\
    

    图片转为tensor格式

    torch::Tensor process(cv::Mat& image, torch::Device device,int img_size)
    {
        cv::resize(image, image, cv::Size(img_size,img_size));//此处将图像尺寸转化为你模型输出的尺寸,不然会报错
        cv::cvtColor(image, image, cv::COLOR_BGR2RGB);// bgr -> rgb
        std::vector<int64_t> dims = {1,img_size,img_size, 3 };
        torch::Tensor img_var = torch::from_blob(image.data, dims, torch::kByte).to(device);//将图像转化成张量
        img_var = img_var.permute({ 0,3,1,2 });//将张量的参数顺序转化为 torch输入的格式 1,3,224,224
        img_var = img_var.toType(torch::kFloat);
        img_var = img_var.div(255);
    
        return img_var;
    
    }
    

    QImage和Mat格式互相转化

    QImage cvMat2QImage(const cv::Mat& mat)
    {
        // 8-bits unsigned, NO. OF CHANNELS = 1
        if(mat.type() == CV_8UC1)
        {
            QImage image(mat.cols, mat.rows, QImage::Format_Indexed8);
            // Set the color table (used to translate colour indexes to qRgb values)
            image.setColorCount(256);
            for(int i = 0; i < 256; i++)
            {
                image.setColor(i, qRgb(i, i, i));
            }
            // Copy input Mat
            uchar *pSrc = mat.data;
            for(int row = 0; row < mat.rows; row ++)
            {
                uchar *pDest = image.scanLine(row);
                memcpy(pDest, pSrc, mat.cols);
                pSrc += mat.step;
            }
            return image;
        }
        // 8-bits unsigned, NO. OF CHANNELS = 3
        else if(mat.type() == CV_8UC3)
        {
            // Copy input Mat
            const uchar *pSrc = (const uchar*)mat.data;
            // Create QImage with same dimensions as input Mat
            QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
            return image.rgbSwapped();
        }
        else if(mat.type() == CV_8UC4)
        {
            qDebug() << "CV_8UC4";
            // Copy input Mat
            const uchar *pSrc = (const uchar*)mat.data;
            // Create QImage with same dimensions as input Mat
            QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
            return image.copy();
        }
        else
        {
            qDebug() << "ERROR: Mat could not be converted to QImage.";
            return QImage();
        }
    }
    cv::Mat QImage2cvMat(QImage image)
    {
        cv::Mat mat;
        qDebug() << image.format();
        switch(image.format())
        {
        case QImage::Format_ARGB32:
        case QImage::Format_RGB32:
        case QImage::Format_ARGB32_Premultiplied:
            mat = cv::Mat(image.height(), image.width(), CV_8UC4, (void*)image.constBits(), image.bytesPerLine());
            break;
        case QImage::Format_RGB888:
            mat = cv::Mat(image.height(), image.width(), CV_8UC3, (void*)image.constBits(), image.bytesPerLine());
            cv::cvtColor(mat, mat, CV_BGR2RGB);
            break;
        case QImage::Format_Indexed8:
            mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void*)image.constBits(), image.bytesPerLine());
            break;
        }
        return mat;
    }
    

    模型调用

     using torch::jit::script::Module;
     QString path;
     QDir dir;
     path=QDir::currentPath();//这里是获取当前执行文件所在地址
     std::cout << 1 << std::endl;
     path.replace("\\","//");
     std::cout << path.toStdString()<< std::endl;
     String in = path.toStdString() + "/u2netpgpu2.pt";
     std::cout << in << std::endl;
      Module module = torch::jit::load(in);
      //加载pytorch模型
       module.to(torch::kCUDA);
       module.eval();
     // torch::Tensor result = module.forward({img_var}).toTensor();  //前向传播获取结果,还是tensor类型
      //模型返回多个结果,用toTuple,其中elements()[i-1]获取第i个返回值
       auto result = module.forward({ imgs }).toTuple()->elements[0].toTensor();
    

    这一步的坑很多,注意libtorch版本要和你训练模型时的torch和CUDA版本相同,不然会有很多错,还有注意原模型训练后的输出为单个还是多个,单个.toTensor(),多个使用toTuple()。

    将预测出来的数据转化为Mat

    auto ten_wrp = result.squeeze(1);
    torch::Tensor result1 = torch::max(ten_wrp);
    torch::Tensor result2 = torch::min(ten_wrp);
    ten_wrp = (ten_wrp - result2) / (result1 - result2);
    ten_wrp = ten_wrp.permute({ 1, 2, 0 });
    ten_wrp = ten_wrp.mul(255).clamp(0, 255).to(torch::kU8);
    ten_wrp = ten_wrp.to(torch::kCPU);
    cv::Mat resultImg(x, x, CV_8U);//xx为你输入图像的宽高,若图片出现问题则改为模型输出的宽高
    std::memcpy((void*)resultImg.data, ten_wrp.data_ptr(), sizeof(torch::kU8) *ten_wrp.numel());
    

    qt文件打包成exe文件移植到其他电脑

    1.将release文件下的exe文件移出来放进一个空文件夹中;
    在这里插入图片描述
    2.使用qt自带的编译器,然后命令行进入上面的文件夹中,使用cd /d 上面exe所在文件夹;在这里插入图片描述
    3.使用windeployqt xx.exe(xx为你exe文件的名字);
    在这里插入图片描述
    4.生成的文件夹中放入相关依赖,缺少的依赖.dll文件有些在你添加的例如opencv和libtorch中未找到去图片中的位置去找;
    在这里插入图片描述
    5.打包成功后可是将其移植到其他未安装相关环境中;
    6.运行成功的图片.在这里插入图片描述

    打包好的文件地址.

    展开全文
  • 这里写自定义目录标题QtChart实现Y轴单曲线,X轴实时时间轴前言在这里插入代码片欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的...

    QtChart实现Y轴单曲线,X轴实时时间轴

    前言

    练手做个实时曲线,以演示采集到的数据。参考了https://www.jianshu.com/p/2c584fa2e469的文章。

    准备工作

    首先,通过QT的帮助文档了解下QChart、QSplineSeries(或者其他的Series类)、QValueAxis等类的描述。
    QChart
    QChart是一个可以在QGraphicsScene中显示的QGraphicsWidget。它管理不同类型的系列和其他图表相关对象(如图例和轴)的图形表示。要简单地在布局中显示图表,可以使用便利类QChartView代替QChart。此外,直线、平滑曲线、面积和散射图可以通过QPolarChart类来表示为极坐标图。
    QSplineSeries
    一个spline series存储QPainterPath绘制平滑曲线所需的数据点和段控制点。当数据发生变化时,控制点会自动计算。该算法对点进行计算,以便绘制平滑曲线。
    QValueAxis
    可以设置一个值轴来显示带有标记、网格线和阴影的轴线。在轴上的值是在标记的位置绘制的。
    QDateTimeAxis
    可以设置QDateTimeAxis来显示带有标记标记、网格线和阴影的轴线。可以通过设置适当的DateTime格式来配置轴线上显示的值。QDateTimeAxis可以表示公元前4714年到公元287396年之间的时间。关于其他与QDateTime相关的信息,请参阅QDateTime文档。
    *void QChart::addSeries(QAbstractSeries series)
    将series添加到chart中,并且chart获得series的所有权,即chart成为series的parent。
    *void QChart::addAxis(QAbstractAxis axis, Qt::Alignment alignment)
    将坐标轴添加到图表中的指定的位置(左边,下方,右边,上方)。这个chart获得坐标轴的所有权。
    *bool QAbstractSeries::attachAxis(QAbstractAxis axis)
    将指定的坐标轴附加给series。
    如果成功,返回true,否则,返回false

    代码实现

    一个简单的演示实时曲线图,可直接运行。``

    import sys
    import random
    from PyQt5.QtChart import QDateTimeAxis,QValueAxis,QSplineSeries,QChart,QChartView
    from PyQt5.QtWidgets import QApplication
    from PyQt5.QtGui import QPainter
    from PyQt5.QtCore import QDateTime,Qt,QTimer
    
    
    class ChartView(QChartView,QChart):
        def __init__(self, *args, **kwargs):
            super(ChartView, self).__init__(*args, **kwargs)
            self.resize(800, 600)
            self.setRenderHint(QPainter.Antialiasing)  # 抗锯齿
            self.chart_init()
            self.timer_init()
        def timer_init(self):
            #使用QTimer,2秒触发一次,更新数据
            self.timer = QTimer(self)
            self.timer.timeout.connect(self.drawLine)
            self.timer.start(2000)
        def chart_init(self):
            self.chart = QChart()
            self.series = QSplineSeries()
            #设置曲线名称
            self.series.setName("实时数据")
            #把曲线添加到QChart的实例中
            self.chart.addSeries(self.series)
            #声明并初始化X轴,Y轴
            self.dtaxisX = QDateTimeAxis()
            self.vlaxisY = QValueAxis()
            #设置坐标轴显示范围
            self.dtaxisX.setMin(QDateTime.currentDateTime().addSecs(-300*1))
            self.dtaxisX.setMax(QDateTime.currentDateTime().addSecs(0))
            self.vlaxisY.setMin(0)
            self.vlaxisY.setMax(1500)
            #设置X轴时间样式
            self.dtaxisX.setFormat("MM月dd hh:mm:ss")
            #设置坐标轴上的格点
            self.dtaxisX.setTickCount(6)
            self.vlaxisY.setTickCount(11)
            #设置坐标轴名称
            self.dtaxisX.setTitleText("时间")
            self.vlaxisY.setTitleText("量程")
            #设置网格不显示
            self.vlaxisY.setGridLineVisible(False)
            #把坐标轴添加到chart中
            self.chart.addAxis(self.dtaxisX,Qt.AlignBottom)
            self.chart.addAxis(self.vlaxisY,Qt.AlignLeft)
            #把曲线关联到坐标轴
            self.series.attachAxis(self.dtaxisX)
            self.series.attachAxis(self.vlaxisY)
    
            self.setChart(self.chart)
        def drawLine(self):
            #获取当前时间
            bjtime = QDateTime.currentDateTime()
            #更新X轴坐标
            self.dtaxisX.setMin(QDateTime.currentDateTime().addSecs(-300*1))
            self.dtaxisX.setMax(QDateTime.currentDateTime().addSecs(0))
            #当曲线上的点超出X轴的范围时,移除最早的点
            if(self.series.count()>149):
                self.series.removePoints(0,self.series.count()-149)
            #产生随即数
            yint = random.randint(0,1500)
            #添加数据到曲线末端
            self.series.append(bjtime.toMSecsSinceEpoch(),yint)
    
    
    if __name__ == "__main__":
        app = QApplication(sys.argv)
        view = ChartView()
        view.show()
        sys.exit(app.exec_())
    
    展开全文
  • VS2017+QT实现折叠/展开布局功能

    千次阅读 2019-12-31 09:56:17
    有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右...列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能...
  • 实现过程与步骤详解Qt的下载安装功能包创建带有GUI的ROS工作空间Qt配置如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个...
  • Qt的界面切换实现

    千次阅读 2019-03-04 13:46:33
    Qt之界面切换创建主窗体模拟密码验证弹出下一个界面功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居...
  • QT5 实现UDP和串口通信

    2021-03-20 18:20:05
    有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右...列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能...
  • QtCreator4.11.1 64位安装2、QWT6.1.4安装实现插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的...
  • 1.实现表头滚动鼠标缩放甘特图 重写HeaderWidget的wheelEvent事件处理 void HeaderWidget ::wheelEvent( QWheelEvent* e ) { DateTimeGrid* const grid = qobject_cast< DateTimeGrid* >(view()->grid...
  • 有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右...列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能...
  • Qt流式布局 最后显示的效果图1: 利用流式实现的效果图2 我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几...增加了支持甘特图的mermaid语法1 功能; 增加了 多屏
  • 有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右...列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能...
  • 基于Linux及QT的即时通信系统的设计与实现

    千次阅读 热门讨论 2020-05-17 16:29:48
    基于Linux及QT的即时通信系统写在前面环境功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右...
  • 有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右...列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能...
  • Python简单使用QtDesigner生成Winform窗体并实现信号signal和槽slot的连接欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片...
  • Qt全局快捷键

    2021-04-06 18:43:20
    QxtGlobalShortcut三方实现欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、...
  • QT象棋暗棋游戏(一)学习目标:学习内容:学习时间:学习产出:欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合...
  • QT中启动python脚本(环境配置+demo)

    千次阅读 2019-06-09 22:39:06
    安装(二)环境配置二、代码实现功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建...
  • QT框架下的文本操作(一)

    千次阅读 2018-10-18 20:00:58
    QT框架下的文本操作模块简介文本类型文本操作代码实现**csv**文件插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚...
  • 项目实现欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右...
  • QT子线程实现串口通信_学习记录1新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右...
  • PyQt5在窗口上显示动态图表

    千次阅读 2020-04-07 23:35:10
    本人正好在做项目中碰到了这种情况,需要动态显示一个甘特图,就以此为例告诉大家怎么实现。首先,直接上完整代码: import sys import matplotlib import datetime matplotlib.use("Qt5Agg") from PyQt5 import ...
  • Tushare股票数据GUI程序

    2020-06-19 11:57:53
    Tushare股票数据GUI项目文章目录Tushare的简单介绍任务使用Qt designer生成基本的用户界面tushare pro的使用如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个...

空空如也

空空如也

1 2
收藏数 27
精华内容 10
关键字:

qt实现甘特图