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

[SFML 2.X] Open Dialog Box - okno wyboru pliku

Ostatnio zmodyfikowano 2024-10-16 14:57
Autor Wiadomość
tBane
Temat założony przez niniejszego użytkownika
» 2024-10-01 17:15:53
Ok. Dodałem długość scroll'a - scrollLength i poprawiłem równania:

C/C++
sf::Vector2f scrollPosition;
scrollPosition.x = position.x + size.x / 4.0f;
scrollPosition.y = position.y + scrollLength * size.x / 4.0f +( scrollValue - minValue ) /( maxValue - scrollLength + 1 - minValue ) *( size.y - scrollLength * size.x / 2.0f ); // HERE
scroll.setPosition( scrollPosition );

C/C++
if( event.type == sf::Event::MouseMoved ) {
   
if( pressed ) {
       
sf::Vector2f mousePos = window->mapPixelToCoords( sf::Vector2i( event.mouseMove.x, event.mouseMove.y ) );
       
       
if( fabs( mousePos.x - mouseStartPos.x ) > 100 ) // Te zachwoanie scrolla w Windowsie jak odjedziesz za daleko w bok
           
 mousePos = mouseStartPos;
       
       
float value =( mousePos.y + mouseOffset.y - position.y ) /( size.y ) *( maxValue - minValue ) + minValue;
       
if( value < minValue )
           
 value = minValue;
       
else if( value > maxValue - scrollLength + 1 ) // HERE
           
 value = maxValue - scrollLength + 1; // HERE
       
       
scrollValue = value;
   
}
}

P-181664
tBane
Temat założony przez niniejszego użytkownika
» 2024-10-01 18:14:56
Jeszcze potrzebuję zrobić tak, by kursor był zawsze na środku scrolla podczas scrollowania, bo obecnie jest na jego początku. Domyślam się, że powinienem edytować wartość:

C/C++
scroll = sf::RectangleShape( sf::Vector2f( size.x, scrollLength * size.x / 2.0f ) );
scroll.setOrigin( 0, scrollLength * size.x / 2.0f );
scroll.setFillColor( sf::Color::Red );

C/C++
sf::Vector2f scrollPosition;
scrollPosition.x = position.x;
scrollPosition.y = position.y + scrollLength * size.x / 2.0f;
scrollPosition.y +=( scrollValue - minValue ) /( maxValue - scrollLength + 1 - minValue ) *( size.y - scrollLength * size.x / 2.0f );
scroll.setPosition( scrollPosition );

P-181665
tBane
Temat założony przez niniejszego użytkownika
» 2024-10-01 20:08:24
Ok udało się :-) Raczej dam radę sam resztę zaprogramować.
// edit
Nie udało się, ale przynajmniej jako tako

C/C++
scrollPosition.y = position.y +( scrollValue - minValue ) /( maxValue - minValue ) *( size.y - scrollLength * size.x / 2.0f );
P-181666
tBane
Temat założony przez niniejszego użytkownika
» 2024-10-01 21:04:51
Opakowałem kod Dialog Box'a w klasę. Teraz zastanawiam się jak zrobić tak, żeby można było zarówno wchodzić w katalogi jak i cofać się.

Text Area:
C/C++
#ifndef TextArea_hpp
#define TextArea_hpp

class TextArea {
public:
   
string s;
   
sf::Vector2f position;
   
sf::Text text;
   
sf::RectangleShape rect;
   
   
TextArea( string s ) {
       
this->s = s;
       
       
text = sf::Text();
       
text.setFont( basicFont );
       
text.setCharacterSize( 16 );
       
text.setString( s );
       
       
sf::Vector2f textPos;
       
textPos.x = position.x + float( text.getCharacterSize() ) * 0.2f;
       
textPos.y = position.y;
       
text.setPosition( textPos );
       
       
// TO-DO size.x
       
sf::Vector2f size;
       
size.x = float( text.getLocalBounds().getSize().x ) * 1.05f;
       
size.y = float( text.getCharacterSize() ) * 1.3f;
       
rect.setSize( size );
   
}
   
   
void setRectSize( sf::Vector2f size ) {
       
rect.setSize( size );
   
}
   
   
void setString( string s ) {
       
this->s = s;
       
text.setString( s );
   
}
   
   
void setPosition( sf::Vector2f position ) {
       
this->position = position;
       
       
rect.setPosition( position );
       
       
sf::Vector2f textPos;
       
textPos.x = position.x + float( text.getCharacterSize() ) * 0.2f;
       
textPos.y = position.y;
       
text.setPosition( textPos );
   
}
   
   
void setCharacterSize( short val ) {
       
       
text.setCharacterSize( val );
       
       
sf::Vector2f size;
       
size.x = float( text.getLocalBounds().getSize().x ) * 1.05f;
       
size.y = float( text.getCharacterSize() ) * 1.3f;
       
rect.setSize( size );
   
}
   
   
void setRectColor( sf::Color color ) {
       
rect.setFillColor( color );
   
}
   
   
void setTextColor( sf::Color color ) {
       
text.setFillColor( color );
   
}
   
   
sf::Vector2f getSize() {
       
return rect.getSize();
   
}
   
   
void update( float dt ) {
       
    }
   
   
void draw() {
       
window->draw( rect );
       
window->draw( text );
   
}
}
;

#endif

Scrollbar:
C/C++
#ifndef Scrollbar_hpp
#define Scrollbar_hpp

class Scrollbar {
public:
   
sf::Vector2f size;
   
sf::Vector2f position;
   
float minValue;
   
float maxValue;
   
float scrollValue;
   
float scrollLength;
   
   
sf::RectangleShape bar;
   
sf::RectangleShape scroll;
   
   
//////////////////////////////////////
   
bool pressed;
   
sf::Vector2f mouseStartPos;
   
sf::Vector2f mouseOffset;
   
//////////////////////////////////////
   
   
Scrollbar( sf::Vector2f size, sf::Vector2f position, float minValue, float maxValue, float scrollValue, float scrollLength ) {
       
this->size = size;
       
this->position = position;
       
       
this->minValue = minValue;
       
this->maxValue = maxValue;
       
this->scrollValue = scrollValue;
       
       
this->scrollLength = scrollLength;
       
       
bar = sf::RectangleShape( size );
       
bar.setFillColor( sf::Color::Blue );
       
       
scroll = sf::RectangleShape( sf::Vector2f( size.x, scrollLength * size.x ) );
       
scroll.setOrigin( 0, 0 );
       
scroll.setFillColor( sf::Color::Red );
       
       
pressed = false;
   
}
   
   
void setValue( int value ) {
       
       
scrollValue = value;
       
       
if( scrollValue > maxValue - scrollLength + 1 )
           
 scrollValue = maxValue - scrollLength + 1;
       
       
if( scrollValue < minValue )
           
 scrollValue = minValue;
       
   
}
   
   
void update( sf::Event & event ) {
       
       
bar.setPosition( position );
       
       
sf::Vector2f scrollPosition;
       
scrollPosition.x = position.x;
       
scrollPosition.y = position.y +( scrollValue - minValue ) /( maxValue - minValue ) *( size.y - scrollLength / 2.0f * size.x );
       
scroll.setPosition( scrollPosition );
       
       
if( event.type == sf::Event::MouseButtonPressed ) {
           
if( event.mouseButton.button == sf::Mouse::Left ) {
               
sf::Vector2f mousePos = window->mapPixelToCoords( sf::Vector2i( event.mouseButton.x, event.mouseButton.y ) );
               
if( scroll.getGlobalBounds().contains( worldMousePosition ) ) {
                   
pressed = true;
                   
mouseStartPos = mousePos;
                   
mouseOffset = scrollPosition - mousePos;
               
}
            }
        }
       
       
if( event.type == sf::Event::MouseButtonReleased ) {
           
if( event.mouseButton.button == sf::Mouse::Left ) {
               
pressed = false;
           
}
        }
       
       
if( event.type == sf::Event::MouseMoved ) {
           
if( pressed ) {
               
sf::Vector2f mousePos = window->mapPixelToCoords( sf::Vector2i( event.mouseMove.x, event.mouseMove.y ) );
               
               
if( fabs( mousePos.x - mouseStartPos.x ) > 100 ) // Te zachwoanie scrolla w Windowsie jak odjedziesz za daleko w bok
                   
 mousePos = mouseStartPos;
               
               
float value =( mousePos.y + mouseOffset.y - position.y ) /( size.y ) *( maxValue - minValue ) + minValue;
               
setValue( value );
           
}
        }
    }
   
   
void draw() {
       
window->draw( bar );
       
window->draw( scroll );
   
}
}
;


#endif

Open Dialog Box:
C/C++
#ifndef OpenDialogBox_hpp
#define OpenDialogBox_hpp

bool sortkey( std::filesystem::directory_entry first, std::filesystem::directory_entry second ) {
   
   
if( first.path().extension() < second.path().extension() )
   
{
       
return true;
   
}
   
return false;
}

class OpenDialogBox {
public:
   
sf::Vector2f position = sf::Vector2f( 300, 300 );
   
sf::RectangleShape rect;
   
sf::RectangleShape titlebar;
   
TextArea * title;
   
sf::RectangleShape submitbar;
   
TextArea * filename; // "Filename" text
   
TextArea * selectedFilename; // selected filename
   
TextButton * submitButton;
   
   
std::string folderPath = "assets";
   
   
sf::RectangleShape textField[ 8 ];
   
std::vector < std::filesystem::directory_entry > paths;
   
TextArea * texts[ 7 ];
   
sf::Sprite icons[ 7 ];
   
   
Scrollbar * scrollbar;
   
   
OpenDialogBox() {
       
rect = sf::RectangleShape( sf::Vector2f( 512, 256 + 32 ) );
       
rect.setFillColor( sf::Color( 64, 64, 64 ) );
       
rect.setPosition( position.x - 256, position.y - 128 - 32 );
       
       
titlebar = sf::RectangleShape( sf::Vector2f( 512, 32 ) );
       
titlebar.setFillColor( sf::Color( 48, 48, 48 ) );
       
titlebar.setPosition( position.x - 256, position.y - 128 - 32 );
       
       
title = new TextArea( "Dialog box" );
       
title->setCharacterSize( 24 );
       
title->setPosition( sf::Vector2f( position.x - 256 + 8, position.y - 128 - 32 ) );
       
title->setRectColor( sf::Color::Transparent );
       
title->setTextColor( textColor );
       
       
paths.clear();
       
if( filesystem::exists( folderPath ) && filesystem::is_directory( folderPath ) ) {
           
for( auto & entry: filesystem::directory_iterator( folderPath ) ) {
               
paths.push_back( entry );
           
}
        }
       
std::sort( paths.begin(), paths.end(), sortkey );
       
       
sf::Vector2f scrollbarSize = sf::Vector2f( 16, 256 - 32 );
       
sf::Vector2f scrollbarPosition = sf::Vector2f( position.x + 256 - scrollbarSize.x, position.y - 128 );
       
scrollbar = new Scrollbar( scrollbarSize, scrollbarPosition, 0, paths.size() - 1, 0, 7 );
       
       
for( int i = 0; i < 7; i++ ) {
           
           
textField[ i ] = sf::RectangleShape( sf::Vector2f( 512, 32 ) );
           
textField[ i ].setFillColor( sf::Color::Transparent );
           
textField[ i ].setPosition( position.x - 256, position.y - 128 + i * 32 );
           
           
texts[ i ] = new TextArea( "location/of/file" );
           
texts[ i ]->setCharacterSize( 20 );
           
texts[ i ]->setRectColor( sf::Color::Transparent );
           
texts[ i ]->setTextColor( textColor );
           
texts[ i ]->setPosition( sf::Vector2f( position.x - 256 + 32 + 4, position.y - 128 + i * 32 + 4 ) );
           
           
icons[ i ] = sf::Sprite();
       
}
       
       
submitbar = sf::RectangleShape( sf::Vector2f( 512, 32 ) );
       
submitbar.setFillColor( sf::Color( 48, 48, 48 ) );
       
       
cam = new Camera();
       
sf::Vector2f pos;
       
       
filename = new TextArea( "File name: " );
       
filename->setCharacterSize( 24 );
       
filename->setRectColor( sf::Color::Transparent );
       
filename->setTextColor( textColor );
       
pos.x = position.x - 256;
       
pos.y = position.y + 256 - 128 - filename->getSize().y;
       
filename->setPosition( pos );
       
       
selectedFilename = new TextArea( "" );
       
selectedFilename->setCharacterSize( 24 );
       
selectedFilename->setRectColor( sf::Color( 48, 48, 48 ) );
       
selectedFilename->setTextColor( textColor );
       
pos.x = position.x - 256 + filename->getSize().x;
       
pos.y = position.y + 256 - 128 - selectedFilename->rect.getSize().y;
       
selectedFilename->setPosition( pos );
       
selectedFilename->setRectSize( sf::Vector2f( 256 + 54, 30 ) );
       
       
       
submitButton = new TextButton( "submit" );
       
pos.x = position.x + 256 - submitButton->rect.getSize().x / 2;
       
pos.y = position.y + 256 - 128 - 16;
       
submitButton->setPosition( pos );
   
}
   
   
void update( sf::Event & event, float dt ) {
       
scrollbar->update( event );
       
       
if( event.type == sf::Event::MouseButtonPressed ) {
           
if( event.mouseButton.button == sf::Mouse::Left ) {
               
               
submitButton->click();
               
               
for( auto & txt: texts ) {
                   
if( txt->text.getGlobalBounds().contains( worldMousePosition ) ) {
                       
selectedFilename->setString( txt->s );
                   
}
                }
               
            }
        }
       
       
for( int i = 0; i < 7; i++ ) {
           
           
texts[ i ]->setString( paths[ i + int( scrollbar->scrollValue ) ].path().string() );
           
           
icons[ i ] = sf::Sprite();
           
string extension = paths[ i + int( scrollbar->scrollValue ) ].path().extension().string();
           
if( extension == "" )
               
 icons[ i ].setTexture( * getTexture( "GUI/icons/dictionary" )->texture );
           
else
               
 icons[ i ].setTexture( * getTexture( "GUI/icons/file" )->texture );
           
           
icons[ i ].setPosition( position.x - 256, position.y - 128 + i * 32 );
       
}
       
       
submitButton->update( dt );
   
}
   
   
void draw() {
       
window->draw( rect );
       
window->draw( titlebar );
       
title->draw();
       
window->draw( submitbar );
       
filename->draw();
       
selectedFilename->draw();
       
submitButton->draw();
       
scrollbar->draw();
       
       
for( int i = 0; i < 7; i++ ) {
           
window->draw( textField[ i ] );
           
texts[ i ]->draw();
           
window->draw( icons[ i ] );
       
}
       
    }
}
;


#endif

użycie Open Dialog Box'a
C/C++
sf::Clock timeClock;
sf::Time prevTime;
sf::Time currentTime;
float dt;

sf::Vector2i mousePosition;
sf::Vector2f worldMousePosition;

bool GUIwasHover;
bool GUIwasClicked;

void testOpenDialogBox() {
   
   
//window->setFramerateLimit(4);
   
OpenDialogBox * openDial = new OpenDialogBox();
   
   
while( window->isOpen() )
   
{
       
prevTime = currentTime;
       
currentTime = timeClock.getElapsedTime();
       
dt = currentTime.asSeconds() - prevTime.asSeconds();
       
       
mousePosition = sf::Mouse::getPosition( * window ); // Pobierz aktualną pozycję myszy względem bieżącego okna
       
worldMousePosition = window->mapPixelToCoords( mousePosition );
       
       
GUIwasHover = false;
       
GUIwasClicked = false;
       
       
sf::Event event;
       
while( window->pollEvent( event ) )
       
{
           
openDial->update( event, dt );
       
}
       
       
       
       
// RENDER
       
window->clear();
       
openDial->draw();
       
window->display();
   
}
   
}
P-181667
madpl1239
» 2024-10-02 19:52:50
Ładnie napisany kod. Trzeba cię pochwalić.
Dzisiaj wszedłem na forum i akurat na twój post. Na początku wydawało się mi, że "wyważasz
otwarte drzwi", przecież jest sporo bibliotek opartych o SFML i nie tylko do "okraszania"
aplikacji ładnymi GUI . Ja ostatnio ściągnąłem z git-a: tgui, imgui. Można powiedzieć, że
te biblioteki wystarczają do różnych aplikacji: i tych "amatorskich" i tych bardziej profesjonalnych
(takich, co to - no wiecie: co coś liczą i wypluwają wyniki w osobnych okienkach, a w innych
okienkach mamy opcje do zmiany parametrów).
Ale czytając dalej i przeglądając kod zacząłem czerpać przyjemność i tak sobie pomyślałem,
przecież to jest fajne zadanie programistyczne napisać taki dialogbox od początku do końca.
Zastanawiam się czy i ja nie popełnie takiego zadania w ramach ćwiczenia:)) Bo różnych swoich
mniejszych, większych aplikacji mam mnóstwo, ale jakoś GUI u mnie zawsze leżało:))
Stąd widząc twoją robotę i zacięcie dostałem tzw. "powera" do zrobienia swojego małego GUI.

Może ten post za bardzo merytoryczny nie jest, ale chciałem tylko powiedzieć, że czasem oglądanie czyjejś
pracy daje kopa, ażeby samemu spróbować. Więc dzięki wielkie za ten temat i trzymać tak dalej!
Programowanie to sztuka sama w sobie - nie ma w niej mistrzów, są tylko mniej i bardziej doświadczeni:)))

P-181668
tBane
Temat założony przez niniejszego użytkownika
» 2024-10-02 23:01:05
Dzięki za docenienie mojej pracy. Ale jeszcze trzeba parę rzeczy dopisać i poprawić np. przemieszczanie się między katalogami, dodać grafikę do scrollbara, poprawić proporcje, skrócić ścieżki do plików. Jak to zrobię to wrzucę kod, bo pewnie się komuś przyda :-)

Jeszcze mam pytanie, czy to dobra metoda na pobranie zaznaczonego pliku ?

C/C++
openDial->update( event, dt );
if( openDial->fileSelected == true ) {
   
openDial->getFilename();
   
openDial = nullptr;
}
P-181669
madpl1239
» 2024-10-03 10:24:29
Ja tu błędu nie widzę, jeżeli chodzi o ten króciutki kod.
Wydaje się poprawne logicznie - zakładając, że openDial->fileSelected
działa poprawnie.

Tylko dlaczego openDial jet na końcu nullptr? Jakie to ma znaczenie?
Czyżby po wyborze openDial kończył działalność.
A co z jego destruktorem? Gdzie on jest? Przecież można by trochę posprzątać
i wyzerować wewnętrzne zmienne obiektu openDial. Domyślny destruktor tego nie robi.

Gdy do openDial przypiszesz nullptr, to nie będzie wycieku pamięci?
Skoro użyłeś w funkcji main()  'new' do zaalokowania openDial na stercie,
to musisz pamiętać, żeby użyć delete do zwolnienia tej RAM. A delete
potrzebuje tego wskaźnika jak wody:))

Więc openDial = nullptr to nie jest dobry pomysł.
No chyba, że użyjesz inteligentnych wskaźników, które same dbają o to
żeby usuwać instancje obiektów, na które wskazują. Tak działa C++

Ale szacun za piękny styl programowania.
P-181670
tBane
Temat założony przez niniejszego użytkownika
» 2024-10-03 17:27:43
Ok. Wrzuciłem tam delete. Nie do końca wiedziałem jak poprawnie usuwać obiekty. Teraz już wiem, dzięki :-)

C/C++
void testOpenDialogBox() {
   
   
//window->setFramerateLimit(4);
   
   
cam = new Camera();
   
   
OpenDialogBox * openDial = new OpenDialogBox();
   
   
while( window->isOpen() )
   
{
       
prevTime = currentTime;
       
currentTime = timeClock.getElapsedTime();
       
dt = currentTime.asSeconds() - prevTime.asSeconds();
       
       
mousePosition = sf::Mouse::getPosition( * window ); // Pobierz aktualną pozycję myszy względem bieżącego okna
       
worldMousePosition = window->mapPixelToCoords( mousePosition );
       
       
GUIwasHover = false;
       
GUIwasClicked = false;
       
       
sf::Event event;
       
while( window->pollEvent( event ) ) {
           
           
if( openDial ) {
               
openDial->update( event, dt );
               
               
if( openDial->fileSelected ) {
                   
cout << openDial->getFilename() << "\n";
                   
delete openDial;
                   
openDial = nullptr;
               
}
            }
        }
       
       
// RENDER
       
window->clear();
       
if( openDial )
           
 openDial->draw();
       
       
window->display();
   
}
   
}
P-181671
1 2 « 3 » 4 5
Poprzednia strona Strona 3 z 5 Następna strona