Рассчитать размер шрифта QGraphicsTextItem на основе масштаба - PullRequest
1 голос
/ 21 июля 2010

У меня QGraphicsTextItem объектов на QGraphicsScene. Пользователь может масштабировать объекты QGraphicsTextItem, перетаскивая углы. (Для этого я использую собственный «редактор преобразования».) Пользователь также может изменить размер QGraphicsTextItem, изменив размер шрифта на панели свойств. То, что я хотел бы сделать, это объединить их так, чтобы, когда пользователь масштабирует объект, перетаскивая угол мышью, он за сценой фактически вычисляет: «Какой размер шрифта необходим, чтобы результирующий объект соответствовал целевому размеру и сохранял масштабный коэффициент на 1,0? "

Что я делаю сейчас, так это позволяю объекту масштабироваться как обычно, используя QGraphicsItem::mouseMoveEvent, а затем вызывая метод FinalizeMapScale в QGraphicsItem::mouseReleaseEvent, как только масштаб мыши будет завершен. Этот метод должен затем изменить шрифт до соответствующего размера и установить масштаб обратно на 1,0.

У меня есть решение, которое работает, но я не без ума от этого. Я относительно новичок в Qt и C ++, поэтому буду признателен за любые комментарии или исправления.

  • Есть ли лучший способ спроектировать все это?
  • Существуют ли методы Qt, которые уже делают это?
  • Мой метод на правильном пути, но есть ошибки Qt или C ++?

Не стесняйтесь комментировать мой ответ ниже и отправьте собственное предпочтительное решение. Спасибо!

[РЕДАКТИРОВАТЬ] В соответствии с запросом в комментариях, вот основы кода масштабирования На самом деле мы пошли в другом направлении, поэтому этот код (и код ниже) больше не используется. Этот код используется в методе mouseMoveEvent, предварительно установив для флага «scaling_» значение true в mousePressEvent, если щелкнуть мышью в правой нижней «горячей точке». Обратите внимание, что этот код находится в декораторе QGraphicsItem, который содержит указатель на цель, которую он масштабирует. Эта абстракция была необходима для нашего проекта, но, вероятно, излишня для большинства целей.

void TransformDecorator::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
  ...
  if (scaling_) {
    QGraphicsItem *target_item = target_->AsQGraphicsItem();
    target_item->setTransformOriginPoint(0.0, 0.0);
    QPointF origin_scene = mapToScene(target_item->transformOriginPoint());
    QPointF scale_position_scene = mapToScene(event->pos());
    qreal unscaled_width = target_item->boundingRect().width();
    qreal scale_x = (scale_position_scene.x() - origin_scene.x()) / unscaled_width;
    if (scale_x * unscaled_width < kMinimumSize) {
      scale_x = kMinimumSize / unscaled_width;
    }
    target_item->setScale(scale_x);
  } else {
    QGraphicsObject::mouseMoveEvent(event);
  }
}

Ответы [ 2 ]

1 голос
/ 21 июля 2010

Пожалуйста, никаких священных войн за конструкцию петли с выходом. Нам это удобно.

void MapTextElement::FinalizeMapScale() {

  // scene_document_width is the width of the text document as it appears in
  // the scene after scaling. After we are finished with this method, we want
  // the document to be as close as possible to this width with a scale of 1.0.
  qreal scene_document_width = document()->size().width() * scale();

  QString text = toPlainText();

  // Once the difference between scene_document_width and the calculated width
  // is below this value, we accept the new font size.
  const qreal acceptable_delta = 1.0;

  // If the difference between scene_document_width and the calculated width is
  // more than this value, we guess at the new font size by calculating a new
  // scale factor. Once it is beneath this value, we creep up (or down) by tiny
  // increments. Without this, we would sometimes incur long "back and forth"
  // loops when using the scale factor.
  const qreal creep_delta = 8.0;
  const qreal creep_increment = 0.1;

  QScopedPointer<QTextDocument> test_document(document()->clone());
  QFont new_font = this->font();
  qreal delta = 0.0;

  // To prevent infinite loops, we store the font size values that we try.
  // Because of the unpredictable (at least to me) relationship between font
  // point size and rendering size, this was the only way I could get it to
  // work reliably.
  QList<qreal> attempted_font_sizes;

  while (true) {

    test_document->setDefaultFont(new_font);
    delta = scene_document_width - test_document->size().width();

    if (std::abs(delta) <= acceptable_delta ||
        attempted_font_sizes.contains(new_font.pointSizeF())) {
      break;
    }

    attempted_font_sizes.append(new_font.pointSizeF());

    qreal new_font_size = 0.0;
    if (std::abs(delta) <= creep_delta) {
      new_font_size = delta > 0.0 ? new_font.pointSizeF() + creep_increment
                                  : new_font.pointSizeF() - creep_increment;
    } else {
      new_font_size = new_font.pointSizeF()
                      * scene_document_width
                      / test_document->size().width();
    }
    new_font.setPointSizeF(new_font_size);
  }

  this->setFont(new_font);
  this->setScale(1.0);
}
0 голосов
/ 02 декабря 2011

Другой способ взглянуть на проблему: Qt масштабировал шрифт, какой эффективный размер шрифта (как он кажется пользователю, а не размер шрифта, заданный в текстовом элементе), который мне нужно отобразить пользователю как их выбор нового размера шрифта? Это всего лишь альтернатива, вам все еще нужен расчет, аналогичный вашему.

У меня похожая проблема. У меня есть текстовый элемент, размер которого (размер одного пикселя) должен быть таким же, как и у других графических элементов других единиц (а затем пользователь может их масштабировать). Какой шрифт (setPointSize) необходимо установить? (Кроме того, что такое setTextWidth и что setDocumentMargin?) Преимущество этого дизайна в том, что вам не нужно обрабатывать масштабирование текстовых элементов иначе, чем масштабирование любой другой формы графического элемента. (Но у меня это пока не работает.)

Кроме того, проблема с пользовательским интерфейсом: если пользователь изменяет размер шрифта, изменится ли размер элемента? Или он остается одинаковым по размеру, а текст переносится по-разному, оставляя более или менее пустое пространство в конце текста? Когда пользователь добавляет новый текст, изменяется ли размер шрифта, чтобы весь текст соответствовал размеру фигуры, или размер фигуры увеличивается, чтобы вместить больше текста? Другими словами, это больше похоже на приложение потоковой диаграммы (где размер фигуры фиксирован, а шрифт сокращается) или как приложение текстового процессора (где размер шрифта постоянен, а форма (количество страниц) увеличивается?

...