[Interest] How to disable dragging feature of Tableview

Poonam Sangale sanglepoonam123 at gmail.com
Fri Apr 7 13:33:08 CEST 2023


How to disable the dragging feature of tableview. I have attached the code
file below.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/interest/attachments/20230407/9d6d7065/attachment.htm>
-------------- next part --------------
#include "ProcessModel.h"

#include <QDebug>
#include <QFontMetrics>
#include <QGuiApplication>

ProcessModel::ProcessModel(QObject *parent) : QAbstractTableModel (parent)
{
    m_roleNames = QAbstractTableModel::roleNames();
    // TODO loop over the QMetaEnum
    m_roleNames.insert(int(Role::Sort), QByteArray("sort"));
    m_roleNames.insert(int(Role::Number), QByteArray("number"));
    m_roleNames.insert(int(Role::Type), QByteArray("type"));
    update();
}

ProcessModel::~ProcessModel()
{

}

QHash<int, QByteArray> ProcessModel::roleNames() const
{
    return m_roleNames;
}

int ProcessModel::rowCount(const QModelIndex &) const
{
    return m_pids.count();
}

int ProcessModel::columnCount(const QModelIndex &) const
{
    return F_CMDLINE + 1;
}

QVariant ProcessModel::data(const QModelIndex &index, int role) const
{
    fields field = fields(index.column());
    int pid = m_pids[index.row()];
    ProcInfo pi = m_proc.procs.value(pid);
    switch (role) {
    case Qt::DisplayRole:
        return pi.toVariant(field);
    case Qt::InitialSortOrderRole: {
        bool numeric = false;
        pi.toVariant(field).toFloat(&numeric);
        if (numeric)
            return Qt::DescendingOrder;
        return Qt::AscendingOrder;
    }
    case int(ProcessModel::Role::Sort):
        return pi.toVariant(field);
    case int(ProcessModel::Role::Number):
        return pi.toVariant(field).toDouble();
    case int(ProcessModel::Role::Type):
        // TODO this is silly: make a virtual in the Category perhaps?
        switch (field) {
        case F_PID:
        case F_PPID:
            return QLatin1String("readonly");
        case F_PGID:
        case F_SID:
            return QLatin1String("id");
        case F_STAT1:
        case F_STAT2:
        case F_STAT3:
        case F_STAT4:
            return QLatin1String("stat");
        case F_CMD:
        case F_CMDLINE:
            return QLatin1String("string");
        default:
            return QLatin1String("string");
        }
    default:
        return QVariant();
    }

    return pi.toVariant(field);
}

QVariant ProcessModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (role != Qt::DisplayRole)
        return QVariant();

    if (orientation == Qt::Horizontal) {
        // section is interpreted as column
        return m_proc.Header_Info.value(static_cast<fields>(section));
    } else {
        return QString();
    }
}

int ProcessModel::columnWidth(int c, const QFont *font)
{
    if (!m_columnWidths[c]) {
        QString header = m_proc.Header_Info.value(static_cast<fields>(c));
        QFontMetrics defaultFontMetrics = QFontMetrics(QGuiApplication::font());
        QFontMetrics fm = (font ? QFontMetrics(*font) : defaultFontMetrics);
        int ret = fm.horizontalAdvance(headerData(c, Qt::Horizontal).toString() + QLatin1String(" ^")) + 8;
        for (int r = 0; r < m_pids.count(); ++r) {
            ProcInfo pi = m_proc.procs.value(m_pids[r]);
            ret = qMax(ret, fm.horizontalAdvance(pi.toVariant(fields(c)).toString()));
        }
        m_columnWidths[c] = ret;
    }
    return m_columnWidths[c];

}

void ProcessModel::update()
{
    qDebug() << __FUNCTION__;
    beginResetModel();
    m_proc.refresh();
    m_pids = m_proc.procs.keys().toVector();
    std::sort(m_pids.begin(), m_pids.end());
    endResetModel();
}




-------------- next part --------------
#include "Proc.h"

#include <QRandomGenerator>
#include <QTime>
#include <random>
std::random_device dev;
std::mt19937 rng(dev());

const QMap<fields, QString> Proc::Header_Info = {
    {F_PID, {"PID"}},
    {F_PPID, {"PPID"}},
    {F_PGID,    {"PGID"}},
    {F_SID,     {"SID"}},
    {F_STAT1,   {"STAT1"}},
    {F_STAT2,   {"STAT2"}},
    {F_STAT3,   {"STAT3"}},
    {F_STAT4,   {"STAT4"}},
    {F_CMD,     {"CMD"}},
    {F_CMDLINE, {"CMDLINE"}}
};

QString random_string(int length=32, QString allow_symbols=QString("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")) {
    QString result;
    QRandomGenerator(QTime::currentTime().msec());
    for (int i = 0; i < length; ++i) {
        std::uniform_int_distribution<std::mt19937::result_type> dist1(0,allow_symbols.length());
        result.append(allow_symbols.at(dist1(rng)));
    }
    return result;
}

ProcInfo::ProcInfo()
{

}

ProcInfo::ProcInfo(int pid)
{
    mpid = pid;
    std::uniform_int_distribution<std::mt19937::result_type> dist1(1,6);
    ppid = dist1(rng);
    std::uniform_int_distribution<std::mt19937::result_type> dist2(0,100);
    pgid = dist2(rng);
    std::uniform_int_distribution<std::mt19937::result_type> dist3(100,1000);
    sid = dist3(rng);
    stat1 = QString("%1%").arg(pgid);
    stat2 = QString("%1 bytes be or not to be is the question.").arg(pgid + sid);
    stat3 = QString("%1 bytes").arg(pgid - sid);
    stat4 = QString("%1 bytes").arg(pgid * sid);
    cmd = random_string();
    cmdline = random_string();
}

ProcInfo::~ProcInfo()
{

}

QVariant ProcInfo::toVariant(fields f)
{
    switch (f) {
    case F_PID:  return mpid;
    case F_PPID:  return ppid;
    case F_PGID:  return pgid;
    case F_SID:  return sid;
    case F_STAT1:  return stat1;
    case F_STAT2:  return stat2;
    case F_STAT3:  return stat3;
    case F_STAT4:  return stat4;
    case F_CMD:  return cmd;
    case F_CMDLINE:  return cmdline;
    default: return "";
    }
}



Proc::Proc()
{

}

void Proc::refresh()
{
    procs.clear();
    std::uniform_int_distribution<std::mt19937::result_type> dist(1000,2500);

    const int numOfPids = dist(rng);

    for (int i = 0; i < numOfPids; ++i)
    {
        procs.insert(i, ProcInfo(i));
    }
}


-------------- next part --------------
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Layouts 1.12
import ProcessModel 0.1
import SortFilterTableModel 0.1
import QtQuick.Controls 2.4
import Qt.labs.qmlmodels 1.0

ApplicationWindow {
    id: window
    visible: true
    width: 1024
    height: 800
    //title: qsTr("05-TableView-DelegateChooser")

    header: ToolBar {
        RowLayout {
            anchors.fill: parent
            anchors.rightMargin: 6
            Switch {
                id: cbUpdate
                checked: true
                text: qsTr("Update every")
            }
            SpinBox {
                id: sbUpdate
                from: 1
                to: 60
                value: 2
                enabled: cbUpdate.checked
            }
            Label {
                text: "sec"
            }
            Button {
                id: resizeCols
                text: qsTr("Resize cols")
                onClicked: {
                    //console.log(table.model.columnCount())
                    for ( var index = 0; index < table.model.columnCount(); ++index) {
                        var width = Math.min(600, table.model.columnWidth(index))
                        //console.log(index + " " + width)
                        headerRepeater.itemAt(index).setWidth(width)
                    }
                    table.forceLayout()
                }
            }

            Item {
                Layout.fillWidth: true
            }
            TextField {
                id: tfFilter
                implicitWidth: parent.width / 4
                onTextEdited: table.contentY = 0
            }
        }
    }
    Row {
        id: header
        width: table.contentWidth
        height: cbUpdate.height
        x: -table.contentX
        z: 1
        spacing: 4
        Repeater {
            id: headerRepeater
            model: table.model.columnCount()
            SortableColumnHeading {
                initialWidth: Math.min(600, table.model.columnWidth(index)); height: parent.height
                text: table.model.headerData(index, Qt.Horizontal)
                initialSortOrder: table.model.initialSortOrder(index)
                onSorting: {
                    for (var i = 0; i < headerRepeater.model; ++i)
                        if (i !== index)
                            headerRepeater.itemAt(i).stopSorting()
                    table.model.sort(index, state == "up" ? Qt.AscendingOrder : Qt.DescendingOrder)
                }
            }
        }
    }
    TableView {
        id: table
        anchors.fill: parent
        anchors.topMargin: header.height
        columnSpacing: 4; rowSpacing: 4
        model: SortFilterTableModel {
            filterText: tfFilter.text
        }
        Timer {
            interval: sbUpdate.value * 1000
            repeat: true
            running: cbUpdate.checked
            onTriggered: table.model.processModel.update()
        }
        columnWidthProvider: function(column) { return headerRepeater.itemAt(column).width }

        delegate: DelegateChooser {
            role: "type"
            DelegateChoice {
                roleValue: "readonly"
                Rectangle {
                    color: "grey"
                    implicitHeight: readonlyText.implicitHeight
                    Text {
                        id: readonlyText
                        text: model.display
                        width: parent.width
                        elide: Text.ElideRight
                        font.preferShaping: false
                    }
                }
            }
            DelegateChoice {
                roleValue: "id"
                Rectangle {
                    color: "yellow"
                    implicitHeight: idText.implicitHeight
                    Text {
                        id: idText
                        text: model.display
                        width: parent.width
                        elide: Text.ElideRight
                        font.preferShaping: false
                    }
                }
            }
            DelegateChoice {
                roleValue: "string"
                Rectangle {
                    color: "#0048BA"
                    implicitHeight: stringText.implicitHeight *1.5

                    Text {
                        id: stringText
                        color: "white"
                        text: model.display
                        width: parent.width
                        elide: Text.ElideRight
                        font.preferShaping: false
                    }
                }
            }
            DelegateChoice {
                Rectangle {
                    color: "#EEE"
                    implicitHeight: defaultText.implicitHeight
                    Text {
                        id: defaultText
                        text: model.display
                        width: parent.width
                        elide: Text.ElideRight
                        horizontalAlignment: Text.AlignRight
                        font.preferShaping: false
                    }
                }
            }
        }
        ScrollBar.horizontal: ScrollBar { }
        ScrollBar.vertical: ScrollBar { }
    }
    Shortcut { sequence: StandardKey.Quit; onActivated: Qt.quit() }
}
-------------- next part --------------
#ifndef PROC_H
#define PROC_H

#include <QMap>
#include <QVariant>
#include <QVector>


enum fields
{
    F_PID = 0,
    F_PPID,
    F_PGID,
    F_SID,
    F_STAT1,
    F_STAT2,
    F_STAT3,
    F_STAT4,
    F_CMD,
    F_CMDLINE,
    F_END = -1
};


class ProcInfo
{
public:
    ProcInfo();
    ProcInfo(int pid);
    ~ProcInfo();

    int mpid;
    int ppid;
    int pgid;
    int sid;
    QString stat1;
    QString stat2;
    QString stat3;
    QString stat4;
    QString cmd;
    QString cmdline;

    QVariant toVariant(fields f);
};

using ProcList = QMap<int, ProcInfo>;


class Proc
{
public:
    Proc();
    void refresh();

    ProcList procs; // processes indexed by pid

    static const QMap<fields, QString> Header_Info;
};

#endif // PROC_H
-------------- next part --------------
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QAbstractTableModel>
#include <QQmlContext>

#include "ProcessModel.h"
#include "SortFilterTableModel.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    qmlRegisterType<ProcessModel>("ProcessModel", 0, 1, "ProcessModel");
    qmlRegisterType<SortFilterTableModel>("SortFilterTableModel", 0, 1, "SortFilterTableModel");

    QQmlApplicationEngine engine;

    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));


    return app.exec();
}

-------------- next part --------------
#ifndef ProcessModel_H
#define ProcessModel_H


#include "Proc.h"

#include <QAbstractTableModel>
#include <QTimer>

class ProcessModel : public QAbstractTableModel
{
    Q_OBJECT

public:
    // supplemental roles beyond Qt::ItemDataRole
    enum class Role {
        Sort = Qt::UserRole,
        Number,
        Type
    };
    Q_ENUM(Role)

    explicit ProcessModel(QObject *parent= nullptr);
    ~ProcessModel();

    QHash<int, QByteArray> roleNames() const override;
    int rowCount(const QModelIndex & = QModelIndex()) const override;
    int columnCount(const QModelIndex & = QModelIndex()) const override;
    QVariant data(const QModelIndex &index, int role) const override;
    QVariant headerData(int section, Qt::Orientation orientation,
                        int role = Qt::DisplayRole) const override;
    Q_INVOKABLE int columnWidth(int c, const QFont *font = nullptr);
    Q_INVOKABLE void update();


private:
    Proc m_proc;
    QVector<int> m_pids;
    QVector<int> m_columnWidths = QVector<int>(F_CMDLINE + 1);
    QHash<int, QByteArray> m_roleNames;
};


#endif

-------------- next part --------------
import QtQuick 2.12

Rectangle {
    id: root
    color: "wheat"
    property int initialSortOrder: Qt.AscendingOrder
    property alias text: label.text
    property real initialWidth: 100
    signal sorting
    width: splitter.x + 6

    function setWidth(newWidth) {
        splitter.x = newWidth -6
    }

    function stopSorting() {
        state = ""
    }

    Text {
        id: label
        anchors.verticalCenter: parent.verticalCenter
        x: 4
        width: parent.width - 4
        text: table.model.headerData(index, Qt.Horizontal)
    }

    Text {
        id: upDownIndicator
        anchors.right: parent.right
        anchors.margins: 8
        anchors.verticalCenter: parent.verticalCenter
        text: "^"
        visible: false
    }

    TapHandler { id: tap; onTapped: nextState() }

    Item {
        id: splitter
        x: root.initialWidth - 6
        width: 12
        height: parent.height
        DragHandler {
            yAxis.enabled: false
            onActiveChanged: {
                if (!active) {
                    if (splitter.x <= 5 ) {
                      splitter.x = 6
                    }
                    table.forceLayout()
                }
            }
        }
        Rectangle {
            anchors.fill: parent
            id: splitterRect
            color: "grey"
            visible: false
        }


        MouseArea {
            hoverEnabled: true
            anchors.fill: parent
            onEntered: splitterRect.visible = true
            onExited: splitterRect.visible = false
        }

    }


    function nextState() {
        if (state == "")
            state = (initialSortOrder == Qt.DescendingOrder ? "down" : "up")
        else if (state == "up")
            state = "down"
        else
            state = "up"
        root.sorting()
    }
    states: [
        State {
            name: "up"
            PropertyChanges { target: upDownIndicator; visible: true; rotation: 0 }
            PropertyChanges { target: root; color: "orange" }
        },
        State {
            name: "down"
            PropertyChanges { target: upDownIndicator; visible: true; rotation: 180 }
            PropertyChanges { target: root; color: "orange" }
        }
    ]
}
-------------- next part --------------
#ifndef SortFilterTableModel_H
#define SortFilterTableModel_H

#include <QObject>
#include <QSortFilterProxyModel>
#include "ProcessModel.h"

class SortFilterTableModel : public QSortFilterProxyModel
{
    Q_OBJECT
    Q_PROPERTY(ProcessModel *processModel READ processModel CONSTANT)
    Q_PROPERTY(QString filterText READ filterText WRITE setFilterText NOTIFY filterTextChanged)
    Q_CLASSINFO("DefaultProperty", "data")
public:
    SortFilterTableModel(QObject *parent = nullptr);

    ProcessModel *processModel() { return &m_ProcessModel; }
    QString filterText() const  {return m_filterText;}
    void setFilterText(QString filterText);
    Q_INVOKABLE void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override;
    int columnCount(const QModelIndex &parent = QModelIndex()) const override;
    Q_INVOKABLE int columnWidth(int c, const QFont *font = nullptr);
    Q_INVOKABLE Qt::SortOrder initialSortOrder(int column) const;

    QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override;
    QModelIndex mapToSource(const QModelIndex &proxyIndex) const override;


signals:
    void filterTextChanged(QString filterText);

private:
    ProcessModel m_ProcessModel;
    QVector<fields> m_fields;
    QString m_filterText;
};

#endif // SortFilterTableModel_H
-------------- next part --------------
#include "SortFilterTableModel.h"
#include <QDebug>

SortFilterTableModel::SortFilterTableModel(QObject *parent)
  : QSortFilterProxyModel (parent)
{
    setSourceModel(&m_ProcessModel);
    setSortRole(int(ProcessModel::Role::Sort));
    // default fields that "top" displays
    m_fields << F_PID
             << F_PPID
             << F_PGID
             << F_SID
             << F_STAT1
             << F_STAT2
             << F_STAT3
             << F_STAT4
             << F_CMD
             << F_CMDLINE;
    setFilterKeyColumn(-1); //With -1: Include all columns to filter
}

void SortFilterTableModel::setFilterText(QString filterText)
{
    if (m_filterText == filterText)
        return;

    m_filterText = filterText;
    setFilterRegularExpression(filterText);
    emit filterTextChanged(m_filterText);
}


void SortFilterTableModel::sort(int column, Qt::SortOrder order)
{
    qDebug() << column << m_fields[column] << order;
    QSortFilterProxyModel::sort(m_fields[column], order);
}

int SortFilterTableModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)
    return m_fields.count();
}

int SortFilterTableModel::columnWidth(int c, const QFont *font)
{
    if (c < 0 || c >= m_fields.count())
        return 0;
    return m_ProcessModel.columnWidth(m_fields[c], font);
}

Qt::SortOrder SortFilterTableModel::initialSortOrder(int column) const
{
    bool ok = false;
    if (column < 0 || column >= m_fields.count())
        return Qt::AscendingOrder;
    int ret = m_ProcessModel.data(m_ProcessModel.index(0, m_fields[column]), Qt::InitialSortOrderRole).toInt(&ok);
    if (ok)
        return Qt::SortOrder(ret);
    else
        return Qt::AscendingOrder;
}

QModelIndex SortFilterTableModel::mapFromSource(const QModelIndex &sourceIndex) const
{
    int row = QSortFilterProxyModel::mapFromSource(sourceIndex).row();
    fields field = fields(sourceIndex.column());
    return m_ProcessModel.index(row, m_fields.indexOf(field));
}

QModelIndex SortFilterTableModel::mapToSource(const QModelIndex &proxyIndex) const
{
    QModelIndex rowIndex = QSortFilterProxyModel::mapToSource(proxyIndex);
    int col = -1;
    if (proxyIndex.column() >= 0 && proxyIndex.column() < m_fields.count())
        col = m_fields[proxyIndex.column()];
    return m_ProcessModel.index(rowIndex.row(), col);
}



More information about the Interest mailing list