[erledigt] Segmentation Fault bei QTextEdit::plainText

Alles rund um die Programmierung mit Qt
Antworten
Godless
Beiträge: 7
Registriert: 25. März 2009 20:21
Wohnort: Karlsruhe

[erledigt] Segmentation Fault bei QTextEdit::plainText

Beitrag von Godless »

Hallo,

ich beschäftige mich noch nicht allzulang mit Qt und schreibe gerade zu Übungszwecken einen kleinen Texteditor. Ich habe mir eine eigene Klasse namens TextEdit von QTextEdit abgeleitet, um z.B. eine open-Methode direkt im Textfeld zu implementieren, was soweit auch funktioniert.

Das Problem liegt beim Speichern: Jedes Mal wenn ich - egal ob zum Setzen per setPlainText() oder zum Auslesen per toPlainText() - auf den plainText zugreife.

Die save-Methode, bei der es hapert, ist recht kurz und sieht folgendermaßen aus:

Code: Alles auswählen

void TextEdit::save(const QString& filePath)
{
    QFile file(filePath);
    QString editContent = QTextEdit::toPlainText();
    // an dieser Stelle bricht die Ausführung des Programmes ab
    // und er sendet mir ein "Segmentation Fault"
    file.write(editContent.toAscii());
}
gdb sagt mir, das Segmentation-Fault-Signal werde von der Methode QTextDocument::isUndoRedoEnabled() gesendet, was mir aber nicht groß weiterhilft, da ich diese Funktion nirgendes aufrufe. Die exakte Fehlermeldung sieht folgendermaßen aus:

Code: Alles auswählen

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7f1a9aded6f0 (LWP 6730)]
0x00007f1a9a46ceb4 in QTextDocument::isUndoRedoEnabled ()
   from /usr/lib/libQtGui.so.4
Hilft das jemandem weiter?

Ich wäre sehr dankbar, wenn mir jemand weiterhelfen könnte. Ich bastle schon seit zwei Tagen an dem Problem, aber es will sich einfach nicht lösen lassen.

MfG Godless
Zuletzt geändert von Godless am 29. März 2009 18:07, insgesamt 1-mal geändert.
Linux for life
Wer braucht Microschrott?
FaS
Beiträge: 184
Registriert: 25. Mai 2006 19:48
Kontaktdaten:

Beitrag von FaS »

toPlainText() ist keine statische Funktion -> lass "QTextEdit::" weg.
Dann wirst du bei der nächsten Zeile den nächsten Fehler erhalten: Bevor in eine Datei geschrieben werden kann, muss sie geöffnet werden. Sie dir die Qt-Dokumentation an.

Gruß,
FaS
pfid
Beiträge: 535
Registriert: 22. Februar 2008 16:59

Beitrag von pfid »

FaS hat geschrieben:toPlainText() ist keine statische Funktion -> lass "QTextEdit::" weg.
Dann wirst du bei der nächsten Zeile den nächsten Fehler erhalten: Bevor in eine Datei geschrieben werden kann, muss sie geöffnet werden. Sie dir die Qt-Dokumentation an.

Gruß,
FaS
Das QTextEdit:: hat in seinem Fall nichts mit statisch zu tun; er ruft hier explizit die Methode der QTextEdit Klasse auf. Würde QTextEdit:: fehlen, würde die Methode (seiner abgeleiteten) TextEdit Klasse aufgerufen.
QTextEdit:: kann jedoch trotzdem weggelassen werden, falls die entsprechende Methode in der Child-Klasse nicht neu oder nicht-virtuell implementiert ist
Zuletzt geändert von pfid am 26. März 2009 09:22, insgesamt 1-mal geändert.
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

abgesehen von den erwähnten Punkten denke ich, dass der Fehler woanderst liegt (vor dem Aufruf von "TextEdit::save()"). Ist die Instanz von "TextEdit" überhaupt gültig? Wo/Wie wird sie erzeugt/verwaltet?
Godless
Beiträge: 7
Registriert: 25. März 2009 20:21
Wohnort: Karlsruhe

Beitrag von Godless »

Upps, da entschuldige ich mich mal, dass ich die Dokumentation nicht sorgfältig gelesen habe :oops: Das .open() hat leider auch nichts genützt, der Fehler bleibt derselbe.

Die Methode ist zwar nicht redefiniert, ich rufe aber trotzdem Methoden von QTextEdit in meiner Klasse so auf. (Einfach eine Angewohnheit, ohne geht's genau so wenig)

Gültig sollte das ganze schon sein, vor allem, da Öffnen und dergleichen problemlos funktioniert. Die Instanz wird in der open-Methode einer von QTabWidget abgeleiteten Klasse erzeugt (dynamisch natürlich), die wie folgt aussieht:

Code: Alles auswählen

void TabWidget::openFile(const QString& path)
{
	TextEdit* edit = new TextEdit(QString(""));
	QString tabTitle = edit->openFile(path);
	int index = QTabWidget::addTab(edit,tabTitle);
	QTabWidget::setCurrentIndex(index);
}
Diese Methode wiederum wird in einem Slot meines Hauptfensters aufgerufen. (Ich weiß, ist ein wenig umständlich, aber ich bin eben so.)
Öffnen etc. funktioniert problemlos. Ich habe es mittlerweile sogar hinbekommen, dass in der open-Methode von TextEdit setPlainText funktioniert. Nur beim Speichern will er wieder nicht.

//Edit: Seltsamerweise funktioniert dieselbe Methode, auf dieselbe Art aufgerufen, in der open-Methode meiner TextEdit-Klasse problemlos!
Zuletzt geändert von Godless am 26. März 2009 18:35, insgesamt 1-mal geändert.
Linux for life
Wer braucht Microschrott?
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Ohne Testcase kommen wir wohl nicht wirklich weiter
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

den Aufruf von "save(..)" sehen wir noch immer nicht...
Godless
Beiträge: 7
Registriert: 25. März 2009 20:21
Wohnort: Karlsruhe

Beitrag von Godless »

Das ist seltsam... auf einmal funktioniert es. Ich kann leider nicht genau sagen, was der Fehler war, da ich sehr viel herumprobiert und nur wenig von dem, was ich umgeändert beibehalten habe. Letztendlich hat es funktioniert, nachdem ich festgestellt habe, dass ich versehentlich die nichtexistente Methode saveFile der Klasse TabWidget aufgerufen habe, statt die des currentWidget(). Warum der Compiler das anstandslos kompiliert hat, ist mir fraglich und obwohl er es getan hat, kann ich mir nicht vorstellen, dass das zu einer Segmentation fault führen würde.

Egal, ich bin froh, dass es jetzt mit folgendem Code in der save()-Methode funktioniert:

Code: Alles auswählen

void TextEdit::saveFile(const QString& fileName)
{
	QFile file(fileName);
	if(!file.open(QIODevice::WriteOnly | QIODevice::Text))
	{
		return;
	}
	QString cont = QTextEdit::toPlainText();
	QByteArray content = cont.toAscii();
	file.write(content);
}
Danke an alle, die versucht haben, mir zu helfen!

MfG Godless

//Edit: Oh mein Gott bin ich blöd! Mir fällt gerade auf wie offensichtlich der Fehler war, den ich gemacht habe: Ich habe - da currentWidget() ja ein QWidget zurückliefert - das ganze zu meiner abgeleiteten TextEdit-Klasse gecastet, die ja ebenfalls indirekt von QWidget erbt. Da ich das currentWidget() vergessen habe, hat er das normale TabWidget genommen und - da es ja ebenfalls von QWidget abgeleitet ist - dieses in ein TextEdit umgewandelt, das natürlich keine save()-Methode hat...
Linux for life
Wer braucht Microschrott?
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

soviel zum Thema
Gültig sollte das ganze schon sein
:wink:

Kleiner Hinweis: genau aus diesem Grund verwendet man für solche Casts "qobject_cast" oder "dynamic_cast":

Code: Alles auswählen

TextEdit *txt = dynamic_cast<TextEdit*>(aWidget);
Q_ASSERT(txt);
Dann hättest du keine zwei Tage gebraucht, sondern nur zwei Sekunden :wink:
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

Godless hat geschrieben:Die Methode ist zwar nicht redefiniert, ich rufe aber trotzdem Methoden von QTextEdit in meiner Klasse so auf.
Sry, ist schon etwas her, wollte da aber nochmal nachhaken.

BITTE BITTE gewohn dir das ab :( Auch wenn es bisher geklappt hat, kannst du da in eine ganz doofe Falle tappen.

Folgendes Beispiel:

Code: Alles auswählen

#include <iostream>
using namespace std;

class A
{
    public:
        void foo()
        {
            bar();
        }
        virtual void bar()
        {
            cout << "A::bar()" << endl;
        }
};

class B : public A
{
    public:
        void bar()
        {
            cout << "B::bar()" << endl;
        }
        void test()
        {
            A::bar();
        }
};

class C : public B
{
    public:
        void bar()
        {
            cout << "C::bar()" << endl;
        }
};

int main()
{
    C c;
    c.bar();
    c.foo();
    c.test();
    return 0;
}
Setze A==QTextEdit, B==deine TextEdit-Klasse.
Dann kommt jemand daher und leitet von deiner TextEdit-klasse ab.
Oder vllt. implementierst du am Ende selber eine der virtuellen Funktionen neu.
Wenn die in irgend einer deiner bereits existierenden Methoden aufgerufen werden soll, und da steht dann immer "QTextEdit::someVirtualFunc()", hast du ein Problem da NIEMALS deine aufegrufen werden kann!!!

Mein Beispiel arbeitet jetzt immer mit cout, aber stell dir vor da passiert mehr hinter den Kulissen, beispielsweise in irgend welchen Models! Plötzlich klappt gar nix mehr!

Wenn du in meinem Beispiel in B::test() den Aufruf "A::bar()" durch "bar()" ersetzt, passt wieder alles, und auch die letzte der 3 Ausgaben liefert "C::bar()", wie man sich das so auch erwarten würde.

Grüße
Franz
Antworten