Перерисовать Canvas в C++ Tizen

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

result
MainForm::OnDraw(void)
{
    __pCanvas->Show();
    __pCanvas->
   Canvas* pCanvas = GetCanvasN();

   if (pCanvas)
   {
      pCanvas->Copy(Point(GetClientAreaBounds().x, GetClientAreaBounds().y),
                    *__pCanvas, GetClientAreaBounds());
      delete pCanvas;
   }
   // Do not call Show(); it is called automatically after OnDraw() callback

   return E_SUCCESS;
}

Вот пример сенсорного метода:

void
MainForm::OnTouchMoved(const Control& source, const Point& currentPosition, const TouchEventInfo& touchInfo)
{
    __pointCount++;
    __strokes[__strokeCount].push_back(currentPosition);
    DrawLine(__prevPosition, currentPosition, Color::GetColor(COLOR_ID_BLACK));
    Tizen::Base::String string;
    string.Append("...");
    string.Append((int)__pointCount);
    __pCanvas->DrawText(Point(50, 300), string);
    __prevPosition = currentPosition;
    Invalidate(false);
    AppLog("OnTouchMoved");
}

И мой метод drawLine():

void
MainForm::DrawLine(const Tizen::Graphics::Point& prevPoint, const Tizen::Graphics::Point& point, const Tizen::Graphics::Color& color)
{
    if (__pCanvas)
    {
        __pCanvas->DrawLine(prevPoint, point);
    }
}

Я не понимаю, почему здесь создается новый холст (почему старый копируется в новый). Почему старый холст не обновляется после вызова drawLine()? Нельзя ли как-то освежить старый холст?

ОБНОВЛЕНИЕ:

После некоторого редактирования мне удалось создать два холста. Я хочу иметь возможность рисовать только в границах __pCanvas, но теперь они «синие», и у меня проблемы с их установкой на «красный».

введите здесь описание изображения

Вот мой код:

result
MainForm::OnInitializing(void)
{
    (...)
    AddTouchEventListener(*this);
    SetMultipointTouchEnabled(false);
    //SetMultipointTouchEnabled(true);

    __pCanvas = new (std::nothrow) Canvas();
    Rectangle rect = Rectangle(GetBounds().x, GetBounds().y, GetBounds().width, GetBounds().height);
    result r = __pCanvas->Construct(rect);

    __pInformationCanvas = new (std::nothrow) Canvas();
    r = __pInformationCanvas->Construct(Rectangle(0, 0, GetBounds().width, verticalDivider));
    if (r == E_SUCCESS)
    {
        __pCanvas->SetBackgroundColor(Color::GetColor(COLOR_ID_WHITE));
        __pCanvas->Clear();

        __pInformationCanvas->SetBackgroundColor(Color::GetColor(COLOR_ID_BLACK));
        __pInformationCanvas->Clear();

        Font font;
        font.Construct(FONT_STYLE_PLAIN, FONT_SIZE);
        __pCanvas->SetFont(font);

        Invalidate(false);
    }

    return E_SUCCESS;
}

И метод onDraw:

result
MainForm::OnDraw(void)
{
    Canvas* pCanvas = GetCanvasN();
    if (pCanvas != null)
    {
        pCanvas->Clear();
        pCanvas->Copy(Point(GetClientAreaBounds().x, GetClientAreaBounds().y),
                      *__pCanvas,
                      GetClientAreaBounds());

        // Copy the second Canvas to the center of the Form's Canvas
        pCanvas->Copy(Point(GetClientAreaBounds().x, GetClientAreaBounds().y),
                      *__pInformationCanvas,
                      __pInformationCanvas->GetBounds());

        delete pCanvas;
    }

    // Do not call Show(). It will be called automatically after OnDraw() callback.
    return E_SUCCESS;
}

person Marek    schedule 27.06.2013    source источник
comment
Таким образом, вы не меняете исходный холст.   -  person    schedule 27.06.2013
comment
Но я хотел бы изменить оригинал... Я не знаю, как я мог... А также в сенсорных методах я меняю исходный холст, поэтому я действительно не понимаю, почему я создаю копию в методе onDraw. Я обновил код.   -  person Marek    schedule 27.06.2013


Ответы (1)


Вы можете рисовать прямо на холсте формы, если хотите. Попробуйте удалить все в OnDraw, кроме оператора return, удалить вызовы Invalidate из OnTouchPressed и OnTouchMoved и заменить MainForm::DrawCircle следующим:

void
MainForm::DrawCircle(const Tizen::Graphics::Point& point, const Tizen::Graphics::Color& color)
{
    Canvas* pCanvas = GetCanvasN();
    if (pCanvas)
    {
        Rectangle rcCircle(Point(point.x - ELLIPSE_RADIUS, point.y - ELLIPSE_RADIUS), Dimension(ELLIPSE_RADIUS * 2, ELLIPSE_RADIUS * 2));
        pCanvas->FillEllipse(color, rcCircle);

        delete pCanvas;
    }
}

Метод, который они предлагают в примере приложения, состоит в том, чтобы иметь отдельный Canvas, в который они рисуют, а затем копировать этот Canvas в форму Canvas в OnDraw. Я бы предположил, что GetCanvasN просто создает новый объект Canvas, описывающий ту же основную поверхность, но могу ошибаться. Не стесняйтесь изучить исходный код Tizen.

Что касается того, почему они предлагают этот метод; причин может быть несколько. Например, если ваш Form когда-либо станет недействительным, вы потеряете все, что вы нарисовали в форме Canvas. Восстановить то, что вы нарисовали с помощью одной команды копирования, очевидно, намного проще, чем повторять каждую команду рисования, которую вы выполняли до этого. в некотором смысле более эффективен при работе с экранными поверхностями.
Или это может быть просто личное предпочтение людей, которые написали пример приложения.


Редактировать. Вот пример использования двух холстов:

Создайте еще один Canvas в MainForm::OnInitializing:

__pCanvas = new (std::nothrow) Canvas();
result r = __pCanvas->Construct(GetBounds());
__pAnotherCanvas = new (std::nothrow) Canvas();
r = __pAnotherCanvas->Construct(Rectangle(0, 0, 100, 64));
if (r == E_SUCCESS)
{
    __pCanvas->SetBackgroundColor(Color::GetColor(COLOR_ID_WHITE));
    __pCanvas->Clear();
    __pAnotherCanvas->SetBackgroundColor(Color::GetColor(COLOR_ID_WHITE));
    __pAnotherCanvas->Clear();
    Invalidate(false);
}

Измените OnDraw, чтобы скопировать оба холста в форму Canvas:

result
MainForm::OnDraw(void)
{
    Canvas* pCanvas = GetCanvasN();
    if (pCanvas != null)
    {
        pCanvas->Clear();
        pCanvas->Copy(Point(GetClientAreaBounds().x, GetClientAreaBounds().y),*__pCanvas, GetClientAreaBounds());

        // Copy the second Canvas to the center of the Form's Canvas
        int cx = GetClientAreaBounds().x + GetClientAreaBounds().width / 2;
        int cy = GetClientAreaBounds().y + GetClientAreaBounds().height / 2;
        pCanvas->Copy(Point(cx - __pAnotherCanvas->GetBounds().width / 2, cy - __pAnotherCanvas->GetBounds().height / 2),
                  *__pAnotherCanvas,
                  __pAnotherCanvas->GetBounds());


         delete pCanvas;
    }
    // Do not call Show(). It will be called automatically after OnDraw() callback.
    return E_SUCCESS;
}

Нарисуйте где-нибудь второй Canvas, например в OnTouchDoublePressed:

void MainForm:: OnTouchDoublePressed(const Control& source, const Point& currentPosition, const TouchEventInfo& touchInfo)
{
    Point point(0, 0);
    String str; str.Format(10, L"x = %d", currentPosition.x);
    __pAnotherCanvas->Clear();
    __pAnotherCanvas->DrawText(point, str, str.GetLength());
    Invalidate(false);
} 

Каждый раз, когда вы дважды щелкаете где-нибудь в клиентской области формы, это будет печатать координату x, где вы щелкнули в центре формы, используя второе Canvas, которое отображается поверх ваших рисунков.

person Michael    schedule 27.06.2013
comment
Думаю, вы знаете, о чем говорите. Не могли бы вы рассказать мне, как я могу реализовать для этого примера два холста: один для рисования и над ним один маленький для отображения некоторых данных каждый раз, когда я двигаю пальцем по холсту? Могу ли я добавить onTouchListener только на холст для рисования, а не на весь холст? Любой пример кода был бы замечательным. Подводя итог, я хочу изменить пример и иметь два холста: один для письма пальцем, а второй для отображения информации. - person Marek; 28.06.2013
comment
Вероятно, вам следует показать макет того, как вы хотите, чтобы выглядел конечный результат, потому что не совсем понятно, что вам действительно нужны два отдельных холста. В любом случае, я обновил свой ответ примером того, как вы можете использовать два холста. - person Michael; 28.06.2013
comment
Информация, которую вы предоставили, очень полезна. Однако есть еще одна вещь. Я хочу иметь возможность рисовать только в области рисования. Теперь, когда я начинаю рисовать и удерживаю кнопку, я могу войти в область __pInformationCanvas и рисовать под ней (потому что размер холста для рисования - это вся (синяя) область. Я хочу, чтобы холст для рисования имел размер второй красной области. Другими словами, когда я вхожу в другую область, кроме области рисования, рисование должно останавливаться (onTouchMoved не должен срабатывать) См. прикрепленное изображение. - person Marek; 01.07.2013