Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[C++ SFML] Schowek - Logika wycinania, wklejania i przesuwania obrazu

Ostatnio zmodyfikowano 2025-08-18 07:51
Autor Wiadomość
tBane
Temat założony przez niniejszego użytkownika
[C++ SFML] Schowek - Logika wycinania, wklejania i przesuwania obrazu
» 2025-08-14 11:47:05
Cześć. Mam problem, którego nie potrafię samodzielnie rozwiąza, a mianowicie wklejanie i wycinanie obrazu.
Na początek przedstawię funkcje kopiowania i wycinania.

C/C++
void copyImage( sf::Image & image ) {
   
sf::Vector2i s( std::min( start_px.x, end_px.x ), std::min( start_px.y, end_px.y ) );
   
sf::Vector2i e( std::max( start_px.x, end_px.x ), std::max( start_px.y, end_px.y ) );
   
   
// copy the image
   
this->img = sf::Image();
   
this->img.create( e.x - s.x, e.y - s.y, sf::Color::Transparent );
   
this->img.copy( image, 0, 0, sf::IntRect( s.x, s.y, e.x - s.x, e.y - s.y ), false );
   
}

void cutImage( sf::Image & image ) {
   
sf::Vector2i s( std::min( start_px.x, end_px.x ), std::min( start_px.y, end_px.y ) );
   
sf::Vector2i e( std::max( start_px.x, end_px.x ), std::max( start_px.y, end_px.y ) );
   
   
// cut the image
   
sf::Image background;
   
background.create( e.x - s.x, e.y - s.y, sf::Color::Transparent );
   
image.copy( background, s.x, s.y, sf::IntRect( 0, 0, e.x - s.x, e.y - s.y ), false );
}

void pasteImage( sf::Image & image ) {
   
sf::Vector2i s( std::min( start_px.x, end_px.x ), std::min( start_px.y, end_px.y ) );
   
sf::Vector2i e( std::max( start_px.x, end_px.x ), std::max( start_px.y, end_px.y ) );
   
   
image.copy( this->img, s.x, s.y, sf::IntRect( 0, 0, this->img.getSize().x, this->img.getSize().y ), true );
   
this->img = sf::Image();
}

Teraz próbuję opakować te funkcje w Eventy i robię to w następujący sposób:
C/C++
if( event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left ) {
   
ElementGUI_pressed = this;
   
   
   
if( tools->toolType == ToolType::Brush || tools->toolType == ToolType::Eraser )
       
 drawPixels( colors_dialog->current_color );
   
   
if( tools->toolType == ToolType::Eraser )
       
 drawPixels( sf::Color::Transparent );
   
   
if( tools->toolType == ToolType::Selector ) {
       
if( selection->clickOnSelection( worldToTile( worldMousePosition, position, size, zoom, zoom_delta ) ) ) {
           
if( !selection->isMoved ) {
               
selection->isMoved = true;
               
selection->setOffset( worldToTile( worldMousePosition, position, size, zoom, zoom_delta ) );
               
               
selection->copyImage( layers_dialog->getCurrentLayer()->image );
               
selection->cutImage( layers_dialog->getCurrentLayer()->image );
           
}
        }
       
else {
           
           
selection->start_px = worldToTile( worldMousePosition, position, size, zoom, zoom_delta );
           
selection->end_px = selection->start_px;
           
selection->isMoved = false;
           
       
}
       
       
selecting = true;
   
}
}

if( event.type == sf::Event::MouseMoved && sf::Mouse::isButtonPressed( sf::Mouse::Left ) ) {
   
   
if( tools->toolType == ToolType::Brush ) {
       
drawPixels( colors_dialog->getCurrentColor() );
   
}
   
   
if( tools->toolType == ToolType::Eraser ) {
       
drawPixels( sf::Color::Transparent );
       
   
}
   
   
if( tools->toolType == ToolType::Selector ) {
       
if( !selection->isMoved ) {
           
selection->end_px = worldToTile( worldMousePosition, position, size, zoom, zoom_delta );
       
}
       
else {
           
selection->move(
           
worldToTile( worldMousePosition, position, size, zoom, zoom_delta ),
           
layers_dialog->getCurrentLayer()->image.getSize()
            )
;
           
selecting = true; // <<< utrzymuj widoczność podczas przenoszenia
       
}
    }
}

if( event.type == sf::Event::MouseButtonReleased && event.mouseButton.button == sf::Mouse::Left ) {
   
if( tools->toolType == ToolType::Selector ) {
       
if( selection->isMoved ) {
           
selection->isMoved = false;
           
selection->pasteImage( layers_dialog->getCurrentLayer()->image );
       
}
       
selecting =( std::abs( selection->start_px.x - selection->end_px.x ) >= 1 ) ||( std::abs( selection->start_px.y - selection->end_px.y ) >= 1 );
   
}
}

No i niestety nie działa. Za każdym razem gdy przesunę zaznaczony fragment obrazu to nadpisuje mi on oryginalny obraz a nie powinien ponieważ nadal jest przesuwany. Obraz powinien być wklejany dopiero gdy zaznaczenie przestaje być aktywne. Chciałbym zrobić poprawnie przenoszenie grafiki ale nie wiem jak to zrobić.. Pomożecie ?

Kodu jest dużo więc wkleiłem istotne fragmenty, ale jeżeli uważasz, że dobrze by było uruchomić projekt u siebie to dorzucam link do repozytorium.
https://github.com/tBane1995/Anim-Paint.git
Powyższy kod znajduje się w pliku "Canvas.hpp" oraz "Selection.hpp"
P-182877
pekfos
» 2025-08-14 21:02:10
Za każdym razem gdy przesunę zaznaczony fragment obrazu to nadpisuje mi on oryginalny obraz a nie powinien ponieważ nadal jest przesuwany.
To czemu to napisałeś w obsłudze puszczenia LPM? Miałoby to więcej sensu w obsłudze naciśnięcia LPM poza obszarem zaznaczenia.
P-182881
tBane
Temat założony przez niniejszego użytkownika
» 2025-08-15 06:06:36
Teraz pierwsze przesunięcie działa, a przy drugim kasuje zaznaczony obraz. Trzeba dodać jakąś flagę z tego co mi się wydaje. Ale jaką to nie mam pojęcia :-/

C/C++
if( event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left ) {
   
ElementGUI_pressed = this;
   
   
   
if( tools->toolType == ToolType::Brush || tools->toolType == ToolType::Eraser )
       
 drawPixels( colors_dialog->current_color );
   
   
if( tools->toolType == ToolType::Eraser )
       
 drawPixels( sf::Color::Transparent );
   
   
if( tools->toolType == ToolType::Selector ) {
       
if( selection->clickOnSelection( worldToTile( worldMousePosition, position, size, zoom, zoom_delta ) ) ) {
           
if( !selection->isMoved ) {
               
selection->isMoved = true;
               
selection->setOffset( worldToTile( worldMousePosition, position, size, zoom, zoom_delta ) );
               
               
selection->copyImage( layers_dialog->getCurrentLayer()->image );
               
selection->cutImage( layers_dialog->getCurrentLayer()->image );
           
}
        }
       
else {
           
selection->pasteImage( layers_dialog->getCurrentLayer()->image );
           
selection->start_px = worldToTile( worldMousePosition, position, size, zoom, zoom_delta );
           
selection->end_px = selection->start_px;
           
selection->isMoved = false;
           
       
}
       
       
selecting = true;
   
}
}
P-182882
pekfos
» 2025-08-15 12:13:23
A tą flagą nie jest selection->isMoved? Jak nie to co ta flaga w ogóle znaczy? Obecny błąd pewnie bierze się z kasowania tej flagi przy puszczeniu LPM.
P-182886
tBane
Temat założony przez niniejszego użytkownika
» 2025-08-15 12:13:34
Udało się ! :D
No więc tak. Należy dodać flagę sprawdzającą czy w zaznaczeniu jest jakiś obraz.

C/C++
void copyImage( sf::Image & image ) {
   
sf::Vector2i s( std::min( start_px.x, end_px.x ), std::min( start_px.y, end_px.y ) );
   
sf::Vector2i e( std::max( start_px.x, end_px.x ), std::max( start_px.y, end_px.y ) );
   
   
// copy the image
   
this->img = sf::Image();
   
this->img.create( e.x - s.x, e.y - s.y, sf::Color::Transparent );
   
this->img.copy( image, 0, 0, sf::IntRect( s.x, s.y, e.x - s.x, e.y - s.y ), false );
   
hasImage = true;
   
}

void cutImage( sf::Image & image ) {
   
sf::Vector2i s( std::min( start_px.x, end_px.x ), std::min( start_px.y, end_px.y ) );
   
sf::Vector2i e( std::max( start_px.x, end_px.x ), std::max( start_px.y, end_px.y ) );
   
   
// cut the image
   
sf::Image background;
   
background.create( e.x - s.x, e.y - s.y, sf::Color::Transparent );
   
image.copy( background, s.x, s.y, sf::IntRect( 0, 0, e.x - s.x, e.y - s.y ), false );
}

void pasteImage( sf::Image & image ) {
   
sf::Vector2i s( std::min( start_px.x, end_px.x ), std::min( start_px.y, end_px.y ) );
   
sf::Vector2i e( std::max( start_px.x, end_px.x ), std::max( start_px.y, end_px.y ) );
   
   
image.copy( this->img, s.x, s.y, sf::IntRect( 0, 0, this->img.getSize().x, this->img.getSize().y ), true );
   
hasImage = false;
   
this->img = sf::Image();
}

I teraz można sprawdzać czy obraz jest w zaznaczeniu i jeżeli nie jest to wtedy kopiować:

C/C++
if( event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left ) {
   
ElementGUI_pressed = this;
   
   
   
if( tools->toolType == ToolType::Brush || tools->toolType == ToolType::Eraser )
       
 drawPixels( colors_dialog->current_color );
   
   
if( tools->toolType == ToolType::Eraser )
       
 drawPixels( sf::Color::Transparent );
   
   
if( tools->toolType == ToolType::Selector ) {
       
if( selection->clickOnSelection( worldToTile( worldMousePosition, position, size, zoom, zoom_delta ) ) ) {
           
if( !selection->isMoved ) {
               
selection->isMoved = true;
               
selection->setOffset( worldToTile( worldMousePosition, position, size, zoom, zoom_delta ) );
               
               
if( !selection->hasImage ) {
                   
selection->copyImage( layers_dialog->getCurrentLayer()->image );
                   
selection->cutImage( layers_dialog->getCurrentLayer()->image );
               
}
            }
        }
       
else {
           
selection->pasteImage( layers_dialog->getCurrentLayer()->image );
           
selection->start_px = worldToTile( worldMousePosition, position, size, zoom, zoom_delta );
           
selection->end_px = selection->start_px;
           
selection->isMoved = false;
           
       
}
       
       
selecting = true;
   
}
}
P-182887
tBane
Temat założony przez niniejszego użytkownika
» 2025-08-15 12:21:52
A tą flagą nie jest selection->isMoved? Jak nie to co ta flaga w ogóle znaczy? Obecny błąd pewnie bierze się z kasowania tej flagi przy puszczeniu LPM.

A ta flaga jest do przesuwania zaznaczania na zasadzie drag and drop
P-182888
tBane
Temat założony przez niniejszego użytkownika
» 2025-08-15 15:50:58
Jeszcze jeden jest problem. Gdy się zaznaczy obszar i szybko się go będzie klikało i przesuwało, to obszar się zmniejsza choć nie powinien.




Wydaje mi się, że to wina tej funkcji:

C/C++
void move( sf::Vector2i point_px, sf::Vector2u map_size ) {
   
   
bool x_reverse = start_px.x > end_px.x;
   
bool y_reverse = start_px.y > end_px.y;
   
   
sf::Vector2i s( std::min( start_px.x, end_px.x ), std::min( start_px.y, end_px.y ) );
   
sf::Vector2i e( std::max( start_px.x, end_px.x ), std::max( start_px.y, end_px.y ) );
   
sf::Vector2i sz = e - s;
   
   
sf::Vector2i newMin = point_px + offset;
   
   
start_px = newMin;
   
end_px = newMin + sz;
   
   
if( start_px.x < 0 ) {
       
start_px.x = 0;
       
end_px.x = sz.x;
   
}
   
   
if( start_px.y < 0 ) {
       
start_px.y = 0;
       
end_px.y = sz.y;
   
}
   
   
if( end_px.x >= map_size.x ) {
       
end_px.x = map_size.x;
       
start_px.x = end_px.x - sz.x;
   
}
   
   
if( end_px.y >= map_size.y ) {
       
end_px.y = map_size.y;
       
start_px.y = end_px.y - sz.y;
   
}
   
   
if( x_reverse == true )
       
 std::swap( start_px.x, end_px.x );
   
   
if( y_reverse == true )
       
 std::swap( start_px.y, end_px.y );
   
   
//std::cout << start_px.x << ", " << start_px.y << "\n";
}
P-182890
tBane
Temat założony przez niniejszego użytkownika
» 2025-08-15 17:21:52
Już błąd fixnięty - wystarczyło skasować obsługę zdarzenia MouseButtonReleased dla LPM i działa :-)

C/C++
if( event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left ) {
   
ElementGUI_pressed = this;
   
   
   
if( tools->toolType == ToolType::Brush || tools->toolType == ToolType::Eraser )
       
 drawPixels( colors_dialog->current_color );
   
   
if( tools->toolType == ToolType::Eraser )
       
 drawPixels( sf::Color::Transparent );
   
   
if( tools->toolType == ToolType::Selector ) {
       
if( selection->clickOnSelection( worldToTile( worldMousePosition, position, size, zoom, zoom_delta ) ) ) {
           
           
if( selection->isMoved == false ) {
               
selection->isMoved = true;
               
selection->setOffset( worldToTile( worldMousePosition, position, size, zoom, zoom_delta ) );
               
               
if( !selection->hasImage ) {
                   
selection->copyImage( layers_dialog->getCurrentLayer()->image );
                   
selection->cutImage( layers_dialog->getCurrentLayer()->image );
               
}
            }
        }
       
else {
           
           
selection->pasteImage( layers_dialog->getCurrentLayer()->image );
           
selection->start_px = worldToTile( worldMousePosition, position, size, zoom, zoom_delta );
           
selection->end_px = selection->start_px;
           
selection->isMoved = false;
           
       
}
    }
}

else if( event.type == sf::Event::MouseMoved && sf::Mouse::isButtonPressed( sf::Mouse::Left ) ) {
   
   
if( tools->toolType == ToolType::Brush ) {
       
drawPixels( colors_dialog->getCurrentColor() );
   
}
   
   
if( tools->toolType == ToolType::Eraser ) {
       
drawPixels( sf::Color::Transparent );
       
   
}
   
   
if( tools->toolType == ToolType::Selector ) {
       
if( selection->isMoved == false ) {
           
//
       
}
       
else {
           
selection->move(
           
worldToTile( worldMousePosition, position, size, zoom, zoom_delta ),
           
layers_dialog->getCurrentLayer()->image.getSize()
            )
;
       
}
    }
}
[ code ]
P-182891
« 1 » 2
  Strona 1 z 2 Następna strona