Wie an bestimmte Position im String navigieren?



  • kernel64 schrieb:

    Habe ein Problem, ich bekomme es nicht hin eine Bedingung aufzustellen wenn man nach die linke Pfeiltaste drückt, dieser solange nach links gehen darf bis zum Promt ende.

    Hier erstmal mein Teil für den Rechtsklick, hier darf der Cursor nur bis zum ende der Eingabe gehen:

    case 0x4D: // Pfeiltaste nach Rechts: 			
    
    						GetConsoleScreenBufferInfo( std_output, &console_screen_buffer_info );
    						x = console_screen_buffer_info.dwCursorPosition.X;
    						y = console_screen_buffer_info.dwCursorPosition.Y;
    
    						if(textpos < input.length() + prompt.length())
    						{
    							textpos++;
    							gotoxy(textpos, y); 					
    							
    						}
    

    Habe es auch für Links versucht, doch meine Bedingung ist falsch:

    case 0x4B: // Pfeiltaste nach Links		
    
    						GetConsoleScreenBufferInfo( std_output, &console_screen_buffer_info );
    						x = console_screen_buffer_info.dwCursorPosition.X;
    						y = console_screen_buffer_info.dwCursorPosition.Y;
    						
    						if(textpos > prompt.length())
    						{
    							textpos--;
    							gotoxy(textpos, y);  												
    						}
    
    						break;
    

    Die unterste Grenze für die Textposition ist 0, die oberste input.length() (es ist besser, wenn du dich bei der Position auf den Eingabestring beziehst, sonst fügst du die Daten noch an der falschen Stelle ein).

    Wenn ich nun nach links gehe und in ein bestehenden string etwas reinschreibe wird der string in der ausgabe nicht nach vorne vorgerückt, damit meine ich die alte ausgabe wird von der neuen überschrieben, wie kann man das verhindern?

    Du mußt nicht nur das neu eingegebene Zeichen schreiben, sondern auch alles, was nach der Einfügestelle kam, neu ausgeben (um eine Stelle nach hinten versetzt).



  • So nun hab ichs geschafft, habe auch versucht es mit einer Switch-Anweisung zu machen, doch da bekomme ich seltsame Reaktionen auf Tasten, musste dann wieder mein altes nehmen 😞 will es auch lieber mit switch machen.

    Bei der clearLineAt() wird alles gelöscht ab der Prompt bis zum Fensterende, hierfür habe ich die Funktion von Improved Console verwendet zum ermitteln der Fensterbreite.

    #include <windows.h>
    #include <string>
    #include <iostream>
    #include <conio.h>
    #include "ic.hpp" //Improved Console
    
    using namespace std; 
    using namespace ic; // Auflösen des Improved Console-Namespace
    
    #pragma comment(lib, "User32.lib")
    
    void clearLineAt(string prompt) 
    {
    	cout.put( '\r' );
    
    	//Lösche alles ab der Prompt bis zum Ende der Konsole (Improved Console)
    	for( string::size_type i = prompt.length(); i < con.getWndSizeX() ; ++i ) 
    	{
    		cout.put( ' ' );
    	}
    
    	cout << '\r' << prompt << flush;
    }
    
    void gotoxy(short x, short y)
    {
    	HANDLE hCon = GetStdHandle(STD_OUTPUT_HANDLE);
    	COORD pos;
    	pos.X = x;
    	pos.Y = y;
    	SetConsoleCursorPosition(hCon, pos);
    }
    
    int main( ) 
    {		
    	bool do_exit = false;
    	string prompt = ":\\>";
    
    	HANDLE std_output = GetStdHandle( STD_OUTPUT_HANDLE );
    	CONSOLE_SCREEN_BUFFER_INFO console_screen_buffer_info;	
    
    	do 
    	{
    		string input;
    		int key, y;
    		int textpos = 0;
    
    		cout << prompt;				
    
    		do 
    		{	
    
    			key = _getch( );
    
    			//Backspace - Löschen
    			if( ( key == 0x08 ) && input.length( ) ) 
    			{ 	
    				clearLineAt( prompt );					
    
    				if(textpos > 0)
    				{										
    					input.erase(textpos-1, 1 );
    					cout << input << flush;					
    
    					GetConsoleScreenBufferInfo( std_output, &console_screen_buffer_info );
    					y = console_screen_buffer_info.dwCursorPosition.Y;
    
    					int currentPosition = prompt.length() + textpos;
    					gotoxy(currentPosition-1, y);  
    					textpos--;						
    				}
    
    			} 
    
    			//Leertaste
    			else if( key == 0x20)
    			{					
    				clearLineAt( prompt );
    				input.insert(textpos, " ");					
    
    				cout << input << flush;
    
    				GetConsoleScreenBufferInfo( std_output, &console_screen_buffer_info );
    				y = console_screen_buffer_info.dwCursorPosition.Y;
    
    				int currentPosition = prompt.length() + textpos;
    				gotoxy(currentPosition+1, y);  
    				textpos++;				
    			}
    
    			//Escape - ESC
    			else if( key == 0x1b ) 
    			{ 
    				textpos = 0;
    				clearLineAt( prompt );
    				input = "";
    			}
    
    			//Steuerzeichen
    			else if( key == 0xe0 ) 
    			{ 
    				switch( _getch( ) ) 
    				{					
    					int x, y;
    
    					case 0x4B: // Pfeiltaste nach Links		
    
    						GetConsoleScreenBufferInfo( std_output, &console_screen_buffer_info );
    						y = console_screen_buffer_info.dwCursorPosition.Y;
    
    						if(textpos > 0)
    						{		
    							int currentPosition = prompt.length() + textpos;
    							gotoxy(currentPosition-1, y);  
    							textpos--;
    						}
    
    						break;
    
    					case 0x4D: // Pfeiltaste nach Rechts: 			
    
    						GetConsoleScreenBufferInfo( std_output, &console_screen_buffer_info );
    						y = console_screen_buffer_info.dwCursorPosition.Y;
    
    						if(textpos < input.length())
    						{		
    							int currentPosition = prompt.length() + textpos;
    							gotoxy(currentPosition+1, y);  
    							textpos++;							
    						}
    
    						break;
    
    					case 0x53: //Entfernen Taste
    
    						if(input.length() != 0)
    						{
    							clearLineAt( prompt );
    							input.erase(textpos, 1 );
    							cout << input << flush;	
    
    							GetConsoleScreenBufferInfo( std_output, &console_screen_buffer_info );
    							y = console_screen_buffer_info.dwCursorPosition.Y;
    
    							int currentPosition = prompt.length() + textpos;
    							gotoxy(currentPosition, y); 
    						}
    
    						break;
    				}
    			} 
    
    			else if( key != '\r' ) 
    			{	
    				string tmp;
    				GetConsoleScreenBufferInfo( std_output, &console_screen_buffer_info );
    				y = console_screen_buffer_info.dwCursorPosition.Y;
    
    				if(textpos < input.length())
    				{
    					clearLineAt( prompt );
    
    					tmp = key;					
    					input.insert(textpos, tmp);
    					//cout.put( key ); 
    					cout << input << flush;
    				}
    				else
    				{
    					input += key; 
    					cout.put( key );															
    				}			
    				int currentPosition = prompt.length() + textpos;
    				gotoxy(currentPosition+1, y);  
    				textpos++;
    			}	
    
    		}while( key != '\r' ); // enter
    
    		cout.put( '\n' );
    
    		if( input.length( ) )
    		{
    			cout << "Input: " << input << " -> " << textpos << endl << endl;				
    		}
    
    		if( input == "exit" ) 
    		{			
    			do_exit = true;
    		}
    
    	} while( !do_exit );
    }
    

    Es ist mir aufefallen wenn ich mit der Backspace Taste alles lösche in nix mehr da steht bewegt sich der Cursor am Anfang der Prompt hin und her _<->_ einmal bei textpos=0 und textpos=1 woran liegt das?

    So jetzt habe ich ein Grundgerüst erstellt, damit kann ich fast weiterarbeiten, was kann man noch verbessern, optimieren am Code?

    Wenn man sich die cmd hierzu anschaut da sehe ich kein Flackern bei der Prompt, wird diese nicht überschrieben wie bei mir und wie kann man das verhindern?



  • @switch: Hast du auch daran gedacht, jeden einzelnen Zweig mit break; zu beenden?

    @Flackern: Vermutlich überschreibt die normale Konsole nur die Zeichen, die sich tatsächlich geändert haben (du überschreibst erst die komplette Zeile mit Leerzeichen, bevor du deine Ausgabe drübersetzt).



  • Habs nochmal in Switch umgewandelt, doch es sind ganz andere Aktionen auf die Tasten und bei der Ausgabe.

    do 
    		{				
    			key = _getch( );
    
    			switch(key)
    			{
    
    			case 0x08: //Backspace
    
    				clearLineAt( prompt );					
    
    				if(textpos > 0)
    				{										
    					input.erase(textpos-1, 1 );
    					cout << input << flush;					
    
    					GetConsoleScreenBufferInfo( std_output, &console_screen_buffer_info );
    					y = console_screen_buffer_info.dwCursorPosition.Y;
    
    					currentPosition = prompt.length() + textpos;
    					gotoxy(currentPosition-1, y);  
    					textpos--;						
    				}
    				break;
    
    			case 0x20: //Leertaste
    
    				clearLineAt( prompt );
    				input.insert(textpos, " ");					
    
    				cout << input << flush;
    
    				GetConsoleScreenBufferInfo( std_output, &console_screen_buffer_info );
    				y = console_screen_buffer_info.dwCursorPosition.Y;
    
    				currentPosition = prompt.length() + textpos;
    				gotoxy(currentPosition+1, y);  
    				textpos++;				
    
    				break;
    
    			case 0x1b: //ESC
    
    				textpos = 0;
    				clearLineAt( prompt );
    				input = "";
    
    				break;
    
    			case 0xe0: //Steuerzeichen
    
    				  switch( _getch( ) ) 
    				  {					
    					  int x, y;
    
    					  case 0x4B: // Pfeiltaste nach Links		
    
    						  GetConsoleScreenBufferInfo( std_output, &console_screen_buffer_info );
    						  y = console_screen_buffer_info.dwCursorPosition.Y;
    
    						  if(textpos > 0)
    						  {		
    							  currentPosition = prompt.length() + textpos;
    							  gotoxy(currentPosition-1, y);  
    							  textpos--;
    						  }
    
    						  break;
    
    					  case 0x4D: // Pfeiltaste nach Rechts: 			
    
    						  GetConsoleScreenBufferInfo( std_output, &console_screen_buffer_info );
    						  y = console_screen_buffer_info.dwCursorPosition.Y;
    
    						  if(textpos < input.length())
    						  {		
    							  currentPosition = prompt.length() + textpos;
    							  gotoxy(currentPosition+1, y);  
    							  textpos++;							
    						  }
    
    						  break;
    
    					  case 0x53: //Entfernen Taste
    
    						  if(input.length() != 0)
    						  {
    							  clearLineAt( prompt );
    							  input.erase(textpos, 1 );
    							  cout << input << flush;	
    
    							  GetConsoleScreenBufferInfo( std_output, &console_screen_buffer_info );
    							  y = console_screen_buffer_info.dwCursorPosition.Y;
    
    							  currentPosition = prompt.length() + textpos;
    							  gotoxy(currentPosition, y); 
    						  }
    
    						  break;
    				  }
    
    				  break;
    			}
    
    			if( key != '\r' ) 
    			{	
    				string tmp;
    				GetConsoleScreenBufferInfo( std_output, &console_screen_buffer_info );
    				y = console_screen_buffer_info.dwCursorPosition.Y;
    
    				if(textpos < input.length())
    				{
    					clearLineAt( prompt );
    
    					tmp = key;					
    					input.insert(textpos, tmp);
    					//cout.put( key ); 
    					cout << input << flush;
    				}
    				else
    				{
    					input += key; 
    					cout.put( key );															
    				}			
    				currentPosition = prompt.length() + textpos;
    				gotoxy(currentPosition+1, y);  
    				textpos++;
    			}
    }while( key != '\r' ); // enter
    

    Wenn ich nun die Pfeiltasten verwende, kommen unbekannte Zeichen in der Ausgabe und Backspace funktioniert nicht, bei Leerzeichen wird eine zuviel freigelassen...



  • Erstmal kannst du auch den Abschnitt "if(key!='\r')..." in den switch mit reinziehen (als default:-Zweig) - und die Behandlung des Leerzeichens stimmt (vermutlich) mit allen anderen "Normaltasten" überein, benötigt also auch keine Sonderbehandlung.

    (und das 'int x,y;' im inneren switch-Block sieht zumindest seltsam aus)

    PS: Und anstelle von '\r' solltest du lieber '\n' als Endekriterium der Schleife verwenden 😉



  • Hab nun den if Teil in default reingepackt:

    default:
    
    				string tmp;
    				GetConsoleScreenBufferInfo( std_output, &console_screen_buffer_info );
    				y = console_screen_buffer_info.dwCursorPosition.Y;
    
    				if(textpos < input.length())
    				{					
    					clearLineAt( prompt );
    
    					tmp = key;					
    					input.insert(textpos, tmp);
    					//cout.put( key ); 
    					cout << input << flush;
    				}
    				else
    				{
    					//cout << "TEST" << endl;
    
    					input += key; 
    					cout.put( key );															
    				}			
    				currentPosition = prompt.length() + textpos;
    				gotoxy(currentPosition+1, y);  
    				textpos++;
    

    Jetzt ist mir aufgefallen wenn ich nix eingebe dann wird außerhalb der Scheife if( input.length( ) ) d.h. input wurde gefüllt, deshalb habe ich eine Test Ausgabe oben in dem else Teil eingebaut und wie man sieht wird diese aufgerufen. Es wird immer ein Zeichen zuviel eingefügt, ich kann z.b. das programm mit exit nicht mehr beenden, außerdem wird gesagt das die Länge = 5 ist.

    Habe auch bei der While-Schleife '\n' eingefügt nun wird aber keine neue Zeile erstellt, muss ich nun auch eine Funktion für ENTER einbauen?



  • kernel64 schrieb:

    Jetzt ist mir aufgefallen wenn ich nix eingebe dann wird außerhalb der Scheife if( input.length( ) ) d.h. input wurde gefüllt, deshalb habe ich eine Test Ausgabe oben in dem else Teil eingebaut und wie man sieht wird diese aufgerufen. Es wird immer ein Zeichen zuviel eingefügt, ich kann z.b. das programm mit exit nicht mehr beenden, außerdem wird gesagt das die Länge = 5 ist.

    Und was heißt das auf deutsch?

    PS: string::insert() kann auch einzelne Zeichen Zeichen einfügen: input.insert(textpos,1/*Anzahl*/,key/*Wert*/); 😉



  • OK jetzt bin ich fertig dank deiner Hilfe 👍 Wie gut das es dich gibt 😉

    #include <windows.h>
    #include <string>
    #include <iostream>
    #include <conio.h>
    #include "ic.hpp" //Improved Console
    
    #pragma comment(lib, "User32.lib")
    
    using namespace std; 
    using namespace ic; // Auflösen des Improved Console-Namespace
    
    #define ENTER			13
    #define BACKSPACE		8
    #define LEERTASTE		32
    #define ESCAPE			27
    #define STEUERZEICHEN	224
    #define PFEIL_LINKS		75
    #define PFEIL_RECHTS	77
    #define DELETE			83
    
    void clearLineAt(string prompt) 
    {
    	cout.put( '\r' );
    
    	//Lösche alles ab der Prompt bis zum Ende der Konsole (Improved Console)
    	for( string::size_type i = prompt.length(); i < con.getWndSizeX() ; ++i ) 
    	{
    		cout.put( ' ' );
    	}
    	//cout << prompt << flush;
    	cout << '\r' << prompt << flush;	
    }
    
    void gotoxy(short x, short y)
    {
    	HANDLE hCon = GetStdHandle(STD_OUTPUT_HANDLE);
    	COORD pos;
    	pos.X = x;
    	pos.Y = y;
    	SetConsoleCursorPosition(hCon, pos);
    }
    
    int main( ) 
    {		
    	bool do_exit = false;
    	string prompt = ":\\>";
    
    	HANDLE std_output = GetStdHandle( STD_OUTPUT_HANDLE );
    	CONSOLE_SCREEN_BUFFER_INFO console_screen_buffer_info;	
    
    	do 
    	{
    		string input;
    		int key, currentPosition, y;
    		int textpos = 0;
    
    		cout << prompt;				
    
    		do 
    		{				
    			key = _getch( );
    
    			switch(key)
    			{
    
    			case BACKSPACE: //Backspace
    
    				clearLineAt( prompt );					
    
    				if(textpos > 0)
    				{										
    					input.erase(textpos-1, 1 );
    					cout << input << flush;					
    
    					GetConsoleScreenBufferInfo( std_output, &console_screen_buffer_info );
    					y = console_screen_buffer_info.dwCursorPosition.Y;
    
    					currentPosition = prompt.length() + textpos;
    					gotoxy(currentPosition-1, y);  
    					textpos--;						
    				}
    				break;
    
    			case ENTER: //Enter == '\r'
    
    				cout << "ENTER" << endl;
    				input.append("\0");
    				//textpos = 0;
    
    				break;
    
    			case LEERTASTE: //Leertaste
    
    				clearLineAt( prompt );
    				input.insert(textpos, " ");					
    
    				cout << input << flush;
    
    				GetConsoleScreenBufferInfo( std_output, &console_screen_buffer_info );
    				y = console_screen_buffer_info.dwCursorPosition.Y;
    
    				currentPosition = prompt.length() + textpos;
    				gotoxy(currentPosition+1, y);  
    				textpos++;				
    
    				break;
    
    			case ESCAPE: //ESC
    
    				textpos = 0;
    				clearLineAt( prompt );
    				input = "";
    
    				break;
    
    			case STEUERZEICHEN: //Steuerzeichen
    
    				  switch( _getch( ) ) 
    				  {	
    					  case PFEIL_LINKS: // Pfeiltaste nach Links								  
    
    						  if(textpos > 0)
    						  {		
    							  GetConsoleScreenBufferInfo( std_output, &console_screen_buffer_info );
    							  y = console_screen_buffer_info.dwCursorPosition.Y;
    
    							  currentPosition = prompt.length() + textpos;
    							  gotoxy(currentPosition-1, y);  
    							  textpos--;
    						  }
    
    						  break;
    
    					  case PFEIL_RECHTS: // Pfeiltaste nach Rechts: 			
    
    						  if(textpos < input.length())
    						  {		
    							  GetConsoleScreenBufferInfo( std_output, &console_screen_buffer_info );
    							  y = console_screen_buffer_info.dwCursorPosition.Y;
    
    							  currentPosition = prompt.length() + textpos;
    							  gotoxy(currentPosition+1, y);  
    							  textpos++;							
    						  }
    
    						  break;
    
    					  case DELETE: //Entfernen Taste
    
    						  if(input.length() != 0)
    						  {
    							  clearLineAt( prompt );
    							  input.erase(textpos, 1 );
    							  cout << input << flush;	
    
    							  GetConsoleScreenBufferInfo( std_output, &console_screen_buffer_info );
    							  y = console_screen_buffer_info.dwCursorPosition.Y;
    
    							  currentPosition = prompt.length() + textpos;
    							  gotoxy(currentPosition, y); 
    						  }
    
    						  break;
    				  }
    				  break;
    
    			default:
    
    				string tmp;
    				GetConsoleScreenBufferInfo( std_output, &console_screen_buffer_info );
    				y = console_screen_buffer_info.dwCursorPosition.Y;
    
    				if(textpos < input.length())
    				{					
    					clearLineAt( prompt );
    
    					tmp = key;					
    					input.insert(textpos, tmp);
    					cout << input << flush;
    				}
    				else
    				{	
    					input += key; 
    					cout.put( key );
    				}			
    				currentPosition = prompt.length() + textpos;
    				gotoxy(currentPosition+1, y);  
    				textpos++;
    
    			}//Switch()
    
    		}while( key != ENTER ); // enter
    
    		cout << endl;
    
    		if( input.length( ) )
    		{
    			cout << "Input: " << input << " -> " << textpos << endl << endl;				
    		}
    
    		if( input == "exit" ) 
    		{			
    			do_exit = true;
    		}
    
    	} while( !do_exit );
    }
    

    Noch eine kleine Hilfe bräuchte ich, das Flackern ärgert mich immernoch, ich weiß das die ganze Zeile gelöscht wird, doch wenn ich z.b. die cout << "\r" auslase, wird die Ausgabe versetzt ausgegeben, was sollte ich nun machen damit die Prompt nur einmal ausgegeben wird bzw. nicht mehr flackert?



  • Das Flackern kommt daher, daß du erst die komplette Zeile mit Leerzeichen überschreibst und anschließend deine (geänderte) Eingabe darüber schreibst - dazwischen liegen zwar nur einige Mikosekunden, aber trotzdem macht sich das bemerkbar. Die einfachste Lösung ist es wohl, nur den mit Leerzeichen zu überschreiben, der auch tatsächlich leer werden soll (das bedeutet: bei ESC die komplette Eingabe, bei Backspace und Del das letzte Zeichen der Eingabe).



  • OK, ich werds mal versuchen, trotzdem vielen Dank 🙂

    Gibts vielleicht noch was anderes zu verbesseren?


Anmelden zum Antworten