www.mikrocontroller.net

Forum: PC-Programmierung Parameter Dialog: Komma anstatt Punkt


Autor: Joe Case (gladi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Zusammen,

ich habe in meinem Programm ein CDialog integriert.
Es soll im Feld als Parameter eine float Zahl eingegeben werden.
Das Problem, es wird Punkt anstatt Komma akzeptiert, z. B. "0.03"
wie kann eine Gleitkommazahl entwieder mit komma oder Punkt angenommen 
werden?

Danke

C/C++ Code:
----------------------------------------------------------.cpp
///////////////////////////////////////////////////////////////////////////// 
// Dialogfeld CKalibrierfaktor 


CKalibrierfaktor::CKalibrierfaktor(CWnd* pParent) 
    : CDialog(CKalibrierfaktor::IDD, pParent) 
{ 
    //{{AFX_DATA_INIT(CKalibrierfaktor) 
    m_fWert = 0.0f; 
    //}}AFX_DATA_INIT 
} 


void CKalibrierfaktor::DoDataExchange(CDataExchange* pDX) 
{ 
    CDialog::DoDataExchange(pDX); 
    //{{AFX_DATA_MAP(CKalibrierfaktor) 
    DDX_Text(pDX, IDC_txtFaktor, m_fWert); 
    DDV_MinMaxFloat(pDX, m_fWert, 0.f, 100.f); 
    //}}AFX_DATA_MAP 
} 


BEGIN_MESSAGE_MAP(CKalibrierfaktor, CDialog) 
    //{{AFX_MSG_MAP(CKalibrierfaktor) 
        // HINWEIS: Der Klassen-Assistent fügt hier Zuordnungsmakros für Nachrichten ein 
    //}}AFX_MSG_MAP 
END_MESSAGE_MAP() 

----------------------------------------------------------.h 

class CKalibrierfaktor : public CDialog 
{ 
// Konstruktion 
public: 
    CKalibrierfaktor(CWnd* pParent = NULL);   // Standardkonstruktor 

// Dialogfelddaten 
    //{{AFX_DATA(CKalibrierfaktor) 
    enum { IDD = IDD_DLGFaktor }; 
    float    m_fWert; 
    //}}AFX_DATA 


// Überschreibungen 
    // Vom Klassen-Assistenten generierte virtuelle Funktionsüberschreibungen 
    //{{AFX_VIRTUAL(CKalibrierfaktor) 
    protected: 
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV-Unterstützung 
    //}}AFX_VIRTUAL 

// Implementierung 
protected: 

    // Generierte Nachrichtenzuordnungsfunktionen 
    //{{AFX_MSG(CKalibrierfaktor) 
        // HINWEIS: Der Klassen-Assistent fügt hier Member-Funktionen ein 
    //}}AFX_MSG 
    DECLARE_MESSAGE_MAP() 
};


Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Indem Du einen String einliest und selber parst.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Besteht die Gefahr, daß deine Benutzer mit 1000-er Seperatoren
arbeiten?
Wenn ja, dann gibt es keine wirklich gute Lösung dafür. Allerdings
sollte man ihnen das IMHO sowieso abgewöhnen. Führt in der Praxis
immer wieder zu Ärger.

Zu deinem Problem.
Die MFC-spezial DDX Makros, mit denen man ein Edit Feld so
einschränken kann, daß eine Zahleneingabe erwartet wird, sind
so in der Praxis sowieso Müll. Lösch einfach mal die Zahl aus
so einem Edit Feld raus (zb. mit einem Backspace) und die MFC
mault rum, daß man bitte eine Zahl eingeben möge. Einen Endbenutzer
kann man damit in den Wahnsinn treiben.

Lösung: Auch Zahleneingaben immer als Texteingaben machen, und
die Umwandlung in eine Zahl dann selbst (zb. mit einem sscanf)
machen. Dann ist es auch einfach im String, den man vom Control
bekommt, alle ',' durch '.' zu ersetzen, sodaß sscanf das richtig
parsen kann. Der Vorteil: Der Benutzer kann dann wahlweise
sowohl ',' als auch '.' als Dezimaltrenner verwenden. Geht aber
klarerweise nur dann, wenn 1000-er Seperatoren nicht benutzt werden.

Wir haben uns dafür spezielle DDX Funktionen geschrieben.
Zb. sowas
void C3dDDX_Text( CDataExchange* pDX, int nIdC, double& d, int Comma = 2 );

void C3dDDX_Text( CDataExchange* pDX, int nIdC, double& d, int Comma /* = 2 */ )
{
  CWnd*   pWnd = pDX->m_pDlgWnd->GetDlgItem( nIdC );
  CString str;

  pDX->PrepareEditCtrl( nIdC );

  ASSERT( pWnd );
  if( pDX->m_bSaveAndValidate ) {
    pWnd->GetWindowText( str );
    
    int n = str.Find( _T( "," ) );
    if( -1 < n ) {
      str.SetAt( n, '.' );
    }

    d = 0;
    _stscanf( str, _T( "%lf" ), &d );
  }

  else {
    TCHAR szBuf[64];
    _stprintf( szBuf, _T( "%-8.*lf" ), Comma, d );
    pWnd->SetWindowText( szBuf );
  }
}

Die haben dann auch noch den netten Nebeneffekt, dass man die
Anzahl der auszugebenden Nachkommastellen sauber definieren
kann.

Wenn der Dialog dann fertig ist, wird die DDX Zeile in DoDataExchange
gegen einen Aufruf so einer Funktion ersetzt:
void CKalibrierfaktor::DoDataExchange(CDataExchange* pDX) 
{ 
    CDialog::DoDataExchange(pDX); 
    //{{AFX_DATA_MAP(CKalibrierfaktor) 
    C3dDDX_Text(pDX, IDC_txtFaktor, m_fWert, 3); 
    //}}AFX_DATA_MAP 
} 

Allerdings spielt dann der Dialogeditor nicht mehr mit. Daher
diesen Austausch erst ganz zum Schluss machen.

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
1000er-Separatoren ließen sich abfangen, indem vor der Konvertierung die 
Anzahl der Punkte und Kommata bestimmt wird bzw. das letzte 
entsprechende Zeichen im String als Dezimal{punkt|komma} verwendet wird:

"1.000,23"

Allerdings bleibt auch dann so etwas wie "1.000" nicht anständig 
interpretierbar.

Autor: Joe Case (gladi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es wird mit 1000-er Seperatoren nicht gearbeitet.

Autor: Joe Case (gladi)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Karl heinz Buchegger,

ganz herzlichen Dank!
Es hat funktioniert.

MfG
gladi

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

Sieh mal nach, ob dein Compiler eine globale Variable 'Decimalseparator' 
kennt. Unter Delphi lässt sich das nämlich ganz einfach einstellen:

decimalseparetor:=',';

MfG Spess

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nein, das kennt der Compiler nicht - das hier ist eine MFC-Anwendung.

Wobei es auch gar nicht dorthin gehört, richtig wäre es, die 
Locale-Informationen über das verwendete Zahlenformat auszuwerten.

Die für das Einlesen von Float-Zahlen verwendbare Funktion atof kann 
sehr wohl auch die Locale-Einstellugen des OS auswerten, dazu muss nur 
im Programm  die Win32-API-Funktion setlocale mit der Kategorie 
LC_NUMERIC und dem entsprechenden Landescode aufgerufen werden.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rufus t. Firefly wrote:
> Nein, das kennt der Compiler nicht - das hier ist eine MFC-Anwendung.
>
> Wobei es auch gar nicht dorthin gehört, richtig wäre es, die
> Locale-Informationen über das verwendete Zahlenformat auszuwerten.

Yep. Das wäre die schöne Lösung.
Der Krampf an der Sache (in meinem/unserem Fall) ist aber, daß
viele Leute aus der Technik daran gewöhnt sind einen Kommapunkt
einzugeben. Und wenn deine Clientel dann aus eine Mischung aus
Punkt und Komma Fetischisten besteht, hast du den A.... offen.

Für uns hat sich die Lösung mit dem String manipulieren
bewährt.
Jeder der schon mal versucht hat eine amerikanische
Datendatei in ein deutsches Excel zu importieren, kennt diesen
Krampf.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.