Как открыть URL в QTableView - PullRequest
8 голосов
/ 04 марта 2010

Как лучше всего представить кликабельный URL в QTableView (или QTreeView, QListView и т. Д.)

Учитывая QStandardItemModel, где некоторые столбцы содержат текст с URL, я бы хотел, чтобы они стали активными, а затем обрабатывали клик, используя QDesktopServices::openURL()

Я надеялся, что найдется какой-нибудь простой способ использовать флаги textInteraction QLabel и поместить их в таблицу. Я не могу поверить, что нет более простого способа справиться с этим. Я действительно надеюсь, что что-то упустил.

Ответы [ 3 ]

6 голосов
/ 04 марта 2010

Вам нужно будет создать делегата для рисования. Код должен выглядеть примерно так:

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();
}
5 голосов
/ 13 декабря 2013

Ну, вы можете использовать делегаты для рендеринга форматированного текста в 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. Обратите внимание, что вам нужно аннулировать роль отображения в модели, чтобы избежать наложения данных.

В любом случае, мне было бы интересно найти лучшее решение, основанное на делегатах.

1 голос
/ 08 марта 2016

К сожалению, не так просто отрисовать QLabel с setOpenExternalLinks() при использовании QTableView (в отличие от QTableWidget). Нет волшебных двух строк кода, которые вы можете вызвать и выполнить работу.

  1. использовать делегата
  2. установить делегата для столбца вашей таблицы
  3. используйте QTextDocument в сочетании с setHTML() для рендеринга ссылки html
  4. это означает, что ваша модель должна предоставить фрагмент HTML, содержащий 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();
}
...