如何在 QTableView 中打开 URL

Posted

技术标签:

【中文标题】如何在 QTableView 中打开 URL【英文标题】:How to open an URL in a QTableView 【发布时间】:2010-03-03 23:15:43 【问题描述】:

QTableView(或QTreeViewQListView 等...)中显示可点击 URL 的最佳方式是什么

给定一个QStandardItemModel,其中一些列包含带有 URL 的文本,我希望它们变为可点击,然后使用 QDesktopServices::openURL() 处理点击

我希望有一些简单的方法可以利用 QLabel 的 textInteraction 标志并将它们塞进表格中。我不敢相信没有更简单的方法来处理这个问题。我真的希望我错过了什么。

【问题讨论】:

【参考方案1】:

您需要创建一个委托来进行绘制。代码应如下所示:

void RenderLinkDelegate::paint(
           QPainter *painter,
           const QStyleOptionViewItem &option,
           const QModelIndex &index
           ) const

    QString text = index.data(Qt::DisplayRole).toString();
    if (text.isEmpty())
        return;

    painter->save();

    // I only wanted it for mouse over, but you'll probably want to remove
    // this condition
    if (option.state & QStyle::State_MouseOver)
    
        QFont font = option.font;
        font.setUnderline(true);
        painter->setFont(font);
        painter->setPen(option.palette.link().color());
    
    painter->drawText(option.rect, Qt::AlignLeft | Qt::AlignVCenter, text);

    painter->restore();

【讨论】:

Kaleb,这是在 tableview 中绘制超链接的唯一方法,并且 topicstarter 想要实现,如何在其中制作可点击的链接,而无需将 QTextBrowser 放入每个单元格。 我很担心,我也可以,如果你知道方法,请告诉我们,怎么做。【参考方案2】:

好吧,您可以使用委托在 qtableview 中渲染富文本,并使用自定义委托重新实现绘制方法,例如:

void ChtmlDelegate::paint(QPainter *painter,
                          const QStyleOptionViewItem &option,
                          const QModelIndex &index) const

    QStyleOptionViewItemV4 opt(option);

    QLabel *label = new QLabel;
    label->setText(index.data().toString());
    label->setTextFormat(Qt::RichText);
    label->setGeometry(option.rect);
    label->setStyleSheet("QLabel  background-color : transparent; ");

    painter->translate(option.rect.topLeft());
    label->render(painter);
    painter->translate(-option.rect.topLeft());

但是,它不会使超链接可点击。

为此,您可以使用以下技巧。重新实现表格/列表视图的 setModel 方法并使用 setIndexWidget。

void MyView::setModel(QAbstractItemModel *m)

  if (!m)
    return;

  QTableView::setModel(m);

  const int rows = model()->rowCount();
  for (int i = 0; i < rows; ++i)
    
      QModelIndex idx = model()->index(i, 1);

      QLabel *label = new QLabel;
      label->setTextFormat(Qt::RichText);
      label->setText(model()->data(idx, CTableModel::HtmlRole).toString());
      label->setOpenExternalLinks(true);

      setIndexWidget(idx, label);
    

在上面的示例中,我将第 1 列替换为 qlabels。请注意,您需要取消模型中的显示角色以避免重叠数据。

无论如何,我会对基于委托的更好解决方案感兴趣。

【讨论】:

什么是CTableModel :: HtmlRole? 'CTableModel' 尚未声明 前一种方法中new QLabel 的内存泄漏怎么办?【参考方案3】:

遗憾的是,使用QTableView(而不是使用QTableWidget)时,用setOpenExternalLinks() 渲染QLabel 并不容易。没有神奇的两行代码可以调用并完成工作。

    使用委托 将委托设置为表格列 使用QTextDocument结合setHTML()来呈现一个html链接 这意味着你的模型需要提供一个包含a href的HTML片段 计算链接的几何形状并提供事件处理程序以拦截鼠标 在链接上改变光标 点击链接时执行动作 真是一团糟:(我想要painter-&gt;setWidgetToCell()

--

void LabelColumnItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const


    if( option.state & QStyle::State_Selected )
        painter->fillRect( option.rect, option.palette.highlight() );


    painter->save();

    QTextDocument document;                         // <---- RichText 
    document.setTextWidth(option.rect.width());

    QVariant value = index.data(Qt::DisplayRole);
    if (value.isValid() && !value.isNull())
    
        document.setHtml(value.toString());        // <---- make sure model contains html

        painter->translate(option.rect.topLeft());
        document.drawContents(painter);        
    

    painter->restore();

【讨论】:

以上是关于如何在 QTableView 中打开 URL的主要内容,如果未能解决你的问题,请参考以下文章

如何将数据发送到 QTableView/QTableWidget (PyQt)

如何在 QTableView 单元格角落绘制三角形以显示可以从列表中选择的模型数据?

如何在 QTableView 上存储图像(Qt 和 openCV)

如何设置qtableview的某一行被选中

从 QTableView 读取和写入文件

如何优化QTableView的性能