如何在 QTableView 中打开 URL

发布于 2024-08-23 12:51:08 字数 308 浏览 9 评论 0原文

QTableView(或QTreeViewQListView、等等...)

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

我希望有一些简单的方法来利用 QLabel 的 textInteraction 标志并将它们填充到表中。我不敢相信没有更简单的方法来处理这个问题。我真的希望我错过了一些东西。

What is the best way to present a clickable URL in a QTableView (or QTreeView, QListView, etc...)

Given a QStandardItemModel where some of the columns contain text with URLs I'd like them to become clickable and then handle the click by using QDesktopServices::openURL()

I was hoping there would be some easy way to leverage QLabel's textInteraction flags and to cram them into the table. I can't believe there's not an easier way to handle this. I really hope I'm missing something.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

痞味浪人 2024-08-30 12:51:09

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

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

You'll need to create a delegate to do the painting. The code should look something like this:

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();
}
凉世弥音 2024-08-30 12:51:09

好吧,您可以使用委托在 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。请注意,您需要取消模型中的显示角色以避免数据重叠。

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

Well, you can use delegates to render rich text in a qtableview with custom delegates reimplementing the paint method such as:

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

However, it will not make hyperlinks clickable.

To do so, you can use the following hack. Reimplement the setModel method of your table/list view and use 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);
    }
}

In the example above, I replace column 1 with qlabels. Note that you need to void the display role in the model to avoid overlapping data.

Anyway, I would be interested in a better solution based on delegates.

萌辣 2024-08-30 12:51:09

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

  1. 使用委托
  2. 将委托设置为表的列
  3. 使用 QTextDocumentsetHTML() 结合使用来呈现 html 链接,
  4. 这意味着您的模型需要提供包含 < code>a href
  5. 计算链接的几何形状并提供事件处理程序以拦截鼠标
    • 当光标位于链接上方时更改光标
    • 点击链接时执行操作
  6. 真是一团糟:( 我想要 painter->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();
}

Sadly, its not that easy to render a QLabel with setOpenExternalLinks() when using a QTableView (as opposed to using a QTableWidget). There are no magic two lines of code you can call and have the job done.

  1. use a delegate
  2. set the delegate to the column of your table
  3. use QTextDocument combined with setHTML() to render a html link
  4. this means your model needs to provide an HTML fragment containing a href
  5. calculate the geometry of the link and provide event handlers for to intercept the mouse
    • change the cursor when it is over the link
    • execute the action when the link is clicked
  6. what a mess :( i want painter->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();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文