Russian Qt Forum
Ноябрь 22, 2024, 07:27 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Нарисовать стрелку внутри rectangle  (Прочитано 4163 раз)
SektorCT
Частый гость
***
Offline Offline

Сообщений: 229


Просмотр профиля
« : Июль 21, 2023, 14:30 »

Всем привет.
Может кто подсказать, имеется обьект Rectangle с заданной шириной и длиной. И вот внутри него мне точно внутри него по границе надо нарисовать стрелку через Shape.
Как понимаю можно через PathMultiline сделать. То есть нужно по ширине его занять, а по длине будет будет острый конец.
Почему хочу нарисовать в rectangle, мне надо эту стрелку двигать, и если будет в rectangle то мне надо двигать его и точки у Shape не придется пересчитывать.
Ну а вторйо вариант это прям в Shape нарисовать стрелку и пересчитывать все точки.
Если у кого есть какой то пример буду признателен.
Записан
kambala
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4747



Просмотр профиля WWW
« Ответ #1 : Июль 21, 2023, 21:59 »

лично я вообще не понял как должна выглядеть эта стрелка и как/куда она будет двигаться. может картинка есть?
Записан

Изучением C++ вымощена дорога в Qt.

UTF-8 has been around since 1993 and Unicode 2.0 since 1996; if you have created any 8-bit character content since 1996 in anything other than UTF-8, then I hate you. © Matt Gallagher
SektorCT
Частый гость
***
Offline Offline

Сообщений: 229


Просмотр профиля
« Ответ #2 : Июль 22, 2023, 09:19 »

лично я вообще не понял как должна выглядеть эта стрелка и как/куда она будет двигаться. может картинка есть?

Вот на данном обьекте стрелка https://ibb.co/Dw6WqzC и она двигается по кругу в зависимости от текущего значения.
Первая мысль это сделать прямоугольник с нужным значением в зависимости от размера всего обьекта, и поместить в него Shape.
Но первое что не понятно так это как в С++ понять углы прямоугольника, где право а где лево.
Записан
kambala
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4747



Просмотр профиля WWW
« Ответ #3 : Июль 22, 2023, 10:59 »

надо было сказать «как в спидометре» Улыбающийся

твой Rectangle — это внешняя черная окружность? не вижу чем рисование стрелки отличается от рисования любой из рисочек. ты знаешь угол наклона стрелки, а ее длина — это радиус большой окружности минус радиус маленькой.

для анимации надо всего лишь угол стрелки изменить, что поменяет координаты ее Shape'а.
Записан

Изучением C++ вымощена дорога в Qt.

UTF-8 has been around since 1993 and Unicode 2.0 since 1996; if you have created any 8-bit character content since 1996 in anything other than UTF-8, then I hate you. © Matt Gallagher
SektorCT
Частый гость
***
Offline Offline

Сообщений: 229


Просмотр профиля
« Ответ #4 : Июль 22, 2023, 14:05 »

надо было сказать «как в спидометре» Улыбающийся

твой Rectangle — это внешняя черная окружность? не вижу чем рисование стрелки отличается от рисования любой из рисочек. ты знаешь угол наклона стрелки, а ее длина — это радиус большой окружности минус радиус маленькой.

для анимации надо всего лишь угол стрелки изменить, что поменяет координаты ее Shape'а.

Нет, rectangle при первом варианте внешнеи границы для стрелки. Будет прозрачным, при изменении значения меняется угол и перемещается невидимый rectangle. Пересчитывать точки в этмо случаи не надо. Но в этом случаи надо из qml передавать в С++ данные о rectangle.(я не знаю что нужно передавать чтоыб понимать как нарисовать внутри стрелку.)
Другой вариант это зная какой размер у стрелки рисовать, и при измении пересчитывать все точки.
Записан
kambala
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4747



Просмотр профиля WWW
« Ответ #5 : Июль 22, 2023, 14:30 »

давай так. какие у тебя входные данные? т.е. по каким данным ты собираешься строить стрелку?

глядя на картинку, предполагаю, что у тебя всё нарисовано кроме стрелки (соответственно, в qml доступны все видимые объекты). из С++ будет приходить значение «скорости» от 0 до 1.2?

«невидимый прямоугольник» — это ж просто координаты обрамляющего стрелку прямоугольника, насколько я понимаю?
« Последнее редактирование: Июль 22, 2023, 14:31 от kambala » Записан

Изучением C++ вымощена дорога в Qt.

UTF-8 has been around since 1993 and Unicode 2.0 since 1996; if you have created any 8-bit character content since 1996 in anything other than UTF-8, then I hate you. © Matt Gallagher
SektorCT
Частый гость
***
Offline Offline

Сообщений: 229


Просмотр профиля
« Ответ #6 : Июль 22, 2023, 14:40 »

давай так. какие у тебя входные данные? т.е. по каким данным ты собираешься строить стрелку?

глядя на картинку, предполагаю, что у тебя всё нарисовано кроме стрелки (соответственно, в qml доступны все видимые объекты). из С++ будет приходить значение «скорости» от 0 до 1.2?

«невидимый прямоугольник» — это ж просто координаты обрамляющего стрелку прямоугольника, насколько я понимаю?

1. Все размеры каждого обьекта это все из С++, и для ширины и длинны стрелки так же есть данные. Есть значение на которое стрелка должна будет поворачиватся, то есть для угла так же значения имеются.
2. Невидимы прямоугольник - как первый вариант что я описал выше да, это по сути было бы обрамлением. Но как я писал выше надо будет из qml послать нужные значения о нем в С++, получить все точки и массивом послать обратно. Но вот как определить левую и правую сторону его чтоыб стрелка правильно смотрела, это я вообще не моуг представить.

Но при другмо варианте без прямоугольника нужно бы было высчитывать все точки не в прямоугольнике а в общем области тахометра.

Это пока начальынй набросок кода.
Код:
Rectangle
{
    id: root

    property QtObject pelData
    property real needleData

    height: pelData.needle.needleLength
    width: pelData.needle.needleWidth

    color:"blue"

    Component.onCompleted:
        console.log(pelData.valueNeedleData, pelData.needle.needleLength)

    Shape
    {
        height:        root.size
        width:         root.size
        layer.enabled: true
        layer.samples: 8

        ShapePath
        {
            id: trackShapePath
            capStyle:    Qt.FlatCap
            fillColor:   "transparent"
            strokeColor: "red"
            strokeWidth: pelData.mainCircleBorderWidth

            PathPolyline {
                id: ppl
                path: [ Qt.point(0.0, 0.0),
                        Qt.point(3.0, 5.0),
                        Qt.point(5.0, 8.0),
                        Qt.point(8.0, 0.0)
                      ]
            }
        }
    }
}
Записан
kambala
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4747



Просмотр профиля WWW
« Ответ #7 : Июль 22, 2023, 18:02 »

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

в твоем случае стрелка двумерная, но это ничего принципиально не меняет. кончик стрелки как раз будет указывать на отметку. зачем тебе передавать координаты стрелки в С++ я не очень понял, ты ж можешь наоборот их оттуда и брать.

надеюсь, суть подхода ясна Улыбающийся как видишь, никакие стороны для стрелки определять отдельно не надо, всё работает «само по себе».
Код
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Window 2.15
import QtQuick.Layouts 1.3
import QtQuick.Shapes 1.15
 
Window {
readonly property real quarterLength: 50
readonly property real minuteLength: 20
readonly property real arrowAngle: Math.PI / 6 // 30
readonly property real arrowLength: 15
 
width: 640
height: 480
visible: true
title: qsTr("Hello World")
 
function polarLineX(angle, length) {
return length * Math.cos(angle)
}
function polarLineY(angle, length) {
return length * Math.sin(angle)
}
 
Rectangle {
id: circle
 
anchors.centerIn: parent
width: Math.min(parent.width, parent.height)
height: width
 
radius: width / 2
border.color: "red"
 
Repeater {
id: tickmarks
 
model: 12
Shape {
id: tickmark
required property int index
readonly property real phi: index * 2 * Math.PI / tickmarks.count
 
x: polarLineX(phi, circle.radius)
y: polarLineY(phi, circle.radius)
transform: Translate {
x: circle.radius
y: circle.radius
}
 
ShapePath {
strokeColor: "blue"
strokeWidth: 1
 
PathLine {
readonly property real tickmarkLength: index % 3 == 0 ? quarterLength : minuteLength
x: polarLineX(tickmark.phi, -tickmarkLength)
y: polarLineY(tickmark.phi, -tickmarkLength)
}
 
PathMove {
x: 0
y: 0
}
PathLine {
readonly property real angle: tickmark.phi + arrowAngle
x: polarLineX(angle, -arrowLength)
y: polarLineY(angle, -arrowLength)
}
 
PathMove {
x: 0
y: 0
}
PathLine {
readonly property real angle: tickmark.phi - arrowAngle
x: polarLineX(angle, -arrowLength)
y: polarLineY(angle, -arrowLength)
}
}
}
}
}
}
 
« Последнее редактирование: Июль 22, 2023, 18:05 от kambala » Записан

Изучением C++ вымощена дорога в Qt.

UTF-8 has been around since 1993 and Unicode 2.0 since 1996; if you have created any 8-bit character content since 1996 in anything other than UTF-8, then I hate you. © Matt Gallagher
kambala
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4747



Просмотр профиля WWW
« Ответ #8 : Июль 22, 2023, 18:41 »

а чтоб в С++ вычислять координаты, задай свою стрелку для случая в 0 градусов (смотрит вправо, на 3 часа) как QPolygonF, а потом просто вращай ее на нужный угол с помощью QTransform
Записан

Изучением C++ вымощена дорога в Qt.

UTF-8 has been around since 1993 and Unicode 2.0 since 1996; if you have created any 8-bit character content since 1996 in anything other than UTF-8, then I hate you. © Matt Gallagher
SektorCT
Частый гость
***
Offline Offline

Сообщений: 229


Просмотр профиля
« Ответ #9 : Июль 22, 2023, 20:03 »

Может быть я не правильно понимаю ваш пример кода, но все тикмарки стали стрелками?)
Мне же надо 1 стрелку сделать, https://ibb.co/2Mj9qX6 вот она. Я по этому и писал что стрелка это 5 точек.
По этому и писал про 2 варианта создания стрелки, или внутри rectangle и его поворачивать по нужному углу, или без rectangle но тогда все точки пересчитывать.
Записан
SektorCT
Частый гость
***
Offline Offline

Сообщений: 229


Просмотр профиля
« Ответ #10 : Июль 22, 2023, 20:13 »

То что я кидал картинку выше это рисунок к которому я стараюсь данный обьект привести. И на нем у меня 2 последние проблемы, это сама стрелка именно такого вида, именно она короткая. И такст что у мажорных тикмарков написана, но это уже совсем другая история.
Записан
kambala
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4747



Просмотр профиля WWW
« Ответ #11 : Июль 22, 2023, 22:09 »

Может быть я не правильно понимаю ваш пример кода, но все тикмарки стали стрелками?)
да. это сделано для примера, т.к. я подумал, что у тебя трудности с рисованием кончика твоей стрелки (диагональных линий). адаптировать уже надо самому Улыбающийся
или без rectangle но тогда все точки пересчитывать.
ну тут вопрос откуда ты хочешь координаты стрелки брать. раз ты говоришь, что тебе в итоге их все равно надо в С++ отправить, то проще там сразу их и вычислить как я написал выше (и не придется трогать полярные координаты), а в QML просто нарисовать Shape/ShapePath по вычисленным координатам (можно забайндить на свойство С++ объекта, которое будет отдавать полигон, тогда все будет работать автоматически, без какого-либо императивного жс кода). Shape — это ведь Item со всеми вытекающими, поэтому непонятно зачем нужен дополнительный невидимый Rectangle.
То что я кидал картинку выше это рисунок к которому я стараюсь данный обьект привести. И на нем у меня 2 последние проблемы, это сама стрелка именно такого вида, именно она короткая.
как короткую нарисовать я уже писал выше (длина = радиус1 - радиус2), да и это ж ровно то же самое, что и отметки рисовать, просто линия не одна.

в твоем примере кода стрелка — это Rectangle, но ведь можно ее сразу Shape делать. Да и координаты там явно как-то должны зависеть от размера рута.

до сих пор не могу понять в чем именно у тебя проблема Улыбающийся айтем стрелки нарисовать? повернуть его можно через свойство rotation / transform.
Записан

Изучением C++ вымощена дорога в Qt.

UTF-8 has been around since 1993 and Unicode 2.0 since 1996; if you have created any 8-bit character content since 1996 in anything other than UTF-8, then I hate you. © Matt Gallagher
SektorCT
Частый гость
***
Offline Offline

Сообщений: 229


Просмотр профиля
« Ответ #12 : Июль 22, 2023, 22:43 »

Кончик стрелки в любом случаи не вариант как мне кажется так рисовать, потмоу что внутри будет заливатся цветом и я нашел вот это

Код:
PathPolyline {
                id: ppl
                path: [ Qt.point(0.0, 0.0),
                        Qt.point(3.0, 5.0),
                        Qt.point(5.0, 8.0),
                        Qt.point(8.0, 0.0)
                      ]
            }

То есть те самые 5 точек из которых должна получистя стрелка. Могли бы показать примером такую стрелку, предположим длинна 12, ширина 5, конец стрелки например 20% от длинны. И например угол для поварота 75 градусов. С таким примером я бы понял как можно модифицировать.
И да, все расчеты в С++ будут, а точнее есть. Но не для стрелки.
И такой вопрос, в вашем примере 2 раза PathMove но на них не завязаны сами PathLine. Как они законекчены друг с другом?
Спасибо
Записан
kambala
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4747



Просмотр профиля WWW
« Ответ #13 : Июль 23, 2023, 10:39 »

да, можно стрелку и через PathPolyline нарисовать (можно и через набор PathLine).
И такой вопрос, в вашем примере 2 раза PathMove но на них не завязаны сами PathLine. Как они законекчены друг с другом?
они как раз завязаны, рисование выполняется последовательно от «текущей точки». мы начинаем с границы окружности и рисуем рисочку, текущая точка становится концом рисочки. но оба куска стрелки мы хотим начать с границы окружности, поэтому возвращаемся в исходную точку 0,0.

вот пример. здесь мы определяем размер стрелки через относительные величины, а потом масштабируем ее до нужного размера через scale (можно и сразу задавать координаты с учетом размера, это не столь существенно). также тут есть небольшая хитрость: стрелка приклеена к маленькой окружности (для случая в 0 градусов), а дальше мы просто выполняем вращение этой окружности, чтоб установить стрелку в нужное положение. в качестве альтернативы можно окружность не вращать, а вращать эфемерный айтем-родитель для стрелки (он будет иметь anchors.fill: smallCircle). но если ты будешь в коде считать координаты заранее, то в этой хитрости нет необходимости.
Код
Rectangle {
id: smallCircle
readonly property real angle: 31
 
anchors.centerIn: parent
width: circle.radius / 3
height: width
 
radius: width / 2
border.color: "black"
 
rotation: angle
 
Shape {
id: arrow
readonly property real arrowLength: circle.radius - smallCircle.radius
readonly property real arrowWidth: 10
readonly property real arrowRelativeLength: 6
readonly property real arrowTipRelativeLength: 2
 
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.right
 
ShapePath {
fillColor: "black"
scale: Qt.size(arrow.arrowLength / arrow.arrowRelativeLength, arrow.arrowWidth)
 
PathPolyline {
readonly property point topLeft: Qt.point(0, 1)
path: [
topLeft,
Qt.point(arrow.arrowRelativeLength - arrow.arrowTipRelativeLength, 1),
Qt.point(arrow.arrowRelativeLength, 0),
Qt.point(arrow.arrowRelativeLength - arrow.arrowTipRelativeLength, -1),
Qt.point(0, -1),
topLeft,
]
}
}
}
}
просто добавить этот элемент после репитера.
Записан

Изучением C++ вымощена дорога в Qt.

UTF-8 has been around since 1993 and Unicode 2.0 since 1996; if you have created any 8-bit character content since 1996 in anything other than UTF-8, then I hate you. © Matt Gallagher
SektorCT
Частый гость
***
Offline Offline

Сообщений: 229


Просмотр профиля
« Ответ #14 : Июль 23, 2023, 19:18 »

Спасибо за пример, в принципе я понял немного его.
Но исходя из того как приходится мне считать в С++ точки для стрелки остаются пара вопросов:
стрелка это 5 точек, 1 и 5 это начало и конец, то есть одинаковые точки.
1 и 2 точки они рядом с центральной окружностью, и угол на котором они должны быть в направлении нужного значения это половина отрезка между ними.
Как лучше их расчитывать если знаем длинну и ширину?
Все 5 точек на одном углу, потом за счет размера их рапределять? То есть 1 и 2 точки это ширина стрелки а значит от угла сдвигать на половину?
Или так расчитывать не правильно?

Это 2 функции что я написал для использования.
Код:
QPointF needle::calculatePoint(const double& radius, const double& angle)
{
    QPointF pointF;
    pointF.setX(m_MainCircleDiameter.value() / 2 + radius * qCos((M_PI * angle) / 180.0));
    pointF.setY(m_MainCircleDiameter.value() / 2 + radius * qSin((M_PI * angle) / 180.0));
    return pointF;
}

double needle::calculateAngle(ScaleEntry& data, ValueRange& range)
{
    AngleValueTransformer angleValueTransformer;
    angleValueTransformer.setAngleRangeDegrees(ValueRange<double>(-150, 150));
    angleValueTransformer.setValueRange(CTcm_ValueRange<double>(range.m_Min, range.m_Max));
    angleValueTransformer.setCurrentValue(data.m_ScaleEntryValue);

    return angleValueTransformer.calculateCurrentAngle();
}

одна функция расчитывает угол иходя их текущего значения и диапазона значений между которыми лежит, и другая функция получает расчитанный угол и радиус.
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.15 секунд. Запросов: 25.