Russian Qt Forum
Март 29, 2024, 00:25 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Странные вещи в передаче данных при работе с QTextBrowser  (Прочитано 9092 раз)
GeorgiiN
Гость
« : Март 01, 2017, 20:47 »

Сразу скажу: я не знаю, к какому форуму это относить. Поскольку проверяю результаты я в QTextBrowser, то отнес все к GUI, но могу ошибаться, ибо так и не получилось понять ошибку.. дело больше в преобразовании, судя по алертам программы. Если я нарушил правила раздела с этой проблемой - прошу не критиковать и перенести тему в необходимый раздел (возможно, для новичков). А еще это длиннопост, в котором я расписываю все подробно - даю все информацию сразу. Если что, простите.   Обеспокоенный

Итак, теперь к сути.

Суть программы - игра "Города". Прописал алгоритм в консоли, все работает шикарно. При переносе в приложение с GUI начался твориться какой-то ад.
В начале, еще в мейне, до вызова application я пробегаю:
Код:
QTextCodec* codec = QTextCodec::codecForName("windows-1251");
    QTextCodec::setCodecForTr(codec);
    QTextCodec::setCodecForCStrings(codec);
    QTextCodec::setCodecForLocale(codec);
У меня, соответственно, Windows 10.

Дальше в приложении я считываю текст из txt файла, создавая структуру для работы. Изначально в консоли я работал с ifstream, но для Qt-GUI я пошел логичным путем - QFile.
Полазив по методичке внутри Creator и почитав форумы, пришел к такой форме:
Код:
dict * firstDict=NULL;/*начало словаря*/
    names * firstNames=NULL; /*начало списка названий городов*/
    dict * currDict; /*указатель для перебора словаря*/
    names * currNames; /*указатель для перебора названий городов*/
    int Number;
QFile file(":/files/Logos/List.txt");
    if (!file.open(QFile::ReadOnly | QFile::Text))
    {
        QMessageBox::warning(this,tr("Ошибка"),tr("Невозможно прочесть директорию"));
        return 0;
    }
    else
    {
        char bufChar = '\0', *bufName;/*буфер для букв и названий городов*/
        QTextStream in(&file);
        in.setCodec("windows-1251");
        while(!in.atEnd())
        {
            QString line = in.readLine(30);/*считываем название из файла*/
            bufName = line.toAscii().data();
.........дальше вы поняли
То есть города я преобразую к Ascii, и все должно быть нормально, как я понял. Но лишь дойдя до этого форума с ошибкой, до которой я хотел, я догадался добавить следующую строчку после вышенаписанного кода:
Код:
ui->display->append(bufName);
Где display - это тот самый QTextBrowser. И вот что он мне начал выдавать:

Вторая попытка с тем же кодом:

Если вместо bufName использовать QString(bufName), то ничего не изменяется. Ну, то есть, изменяется, но страдают так же рандомные города.
При этом для проверки создания структур у меня есть момент с выводом букв и количества городов на эти буквы. Вот сравнение с кодом вывода append и без него, то есть вообще не выводя города при чтении:

Та же проблема есть и при вводе города в строку во время игры. Сначала изображение, а потом код текстом.

Здесь я, собственно, ввожу "Москва". Всегда.
Код:
[u]Главная функция:[/u]
get_city=getcity();
            ui->display->append("GETCITY ПРОШЕЛ");
            ui->display->append(get_city);
            ui->display->append("ВЫШЕ ТО, ЧТО ПРИШЛО");
            c=check_city2(get_city, firstDict);
            ui->display->append("И прочекали");
[u]То, что вы видите первостепенно:[/u]
char* MainWindow::getcity() {
    char* city;
    ui->vvLine->setDisabled(false);
    connect(ui->vvLine,SIGNAL(textChanged(QString)),this,SLOT(TextChanged(QString)));
    QEventLoop *newLoop = new QEventLoop(this);
    connect(ui->vvBut,SIGNAL(clicked()),newLoop,SLOT(quit()));
    newLoop->exec();
    ui->lastcity->setText(ui->vvLine->text());
    ui->display->append("СЕЙЧАС ПРЕОБРАЗУЮ");
    QString str(ui->vvLine->text());
    city = str.toAscii().data();
    ui->vvBut->setDisabled(true);
    ui->vvLine->setDisabled(true);
    ui->vvLine->clear();
    ui->display->append(city);
    city = str.toAscii().data();
    ui->display->append("И ЕЩЕ 2 РАЗА:");
    ui->display->append(city);
    city = str.toAscii().data();
    ui->display->append(city);
    city = str.toAscii().data();
    return city;
}

Если честно, я так и не нашел достоверной инфы, как грамотно выводить *char на "дисплей" QTextBrowser, поэтому я пробовал оба варианта: обычный append(*char) и append(QString(*char)). Работает каждый вариант через раз и очень странно. Он может выдать как введенный город, так и полную кракозябру. На изображении выше лишь один из примеров. С тем же самым кодом он при втором же тесте начал выдавать совершенно иное (другие кракозябры, и "Москва" появляется на третьем выводе или на пятом, но не на первом).

Соответственно, при передаче данных у меня все данные пытаются сравниться с введенными из файла, и выдают ошибки, а программа порой и вовсе вылетает. Наконец-то я нашел, кажется, проблему - append() чудит какую-то магию с жертвой вывода, но я так и не смог понять, какую. Возможно, при решении проблемы append'а у меня и программа будет работать корректно (ибо я изначально ссылался на указатели, которые были скопированы из консоли, где они работали прекрасно).

Еще, может быть, дело в кодировке, но более достоверной инфы я не нашел. Прошу, люди, кто смог осилить это, помогите советом, кто как может. Дело ли в append, или это просто беда кодировки, которая еще и выдает постоянно разные результаты при одинаковых данных.
Я попробовал убрать все append, которые задействуют данные *char, но все равно программа не распознает города на сравнение. Поэтому не знаю, может, и структуры не так формируются в итоге. Может, toAscii неверно работает (то есть не так, как мне надо, и дебил здесь я (но это-то да)). Понятия не имею.

Очень буду рад любым советам и ругательствам, что не до конца прочитал что-то о классах или операциях. И прошу перенести тему, если ей здесь не место, но не наказывать. Всем лучей добра!


Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #1 : Март 02, 2017, 01:56 »

А зачем использовать *char? Используем QString и будет юникод-счастье.
PS. С-строки не-юникод и 0-terminated.
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #2 : Март 02, 2017, 08:28 »

Типичная ошибка новичков.

Код
C++ (Qt)
char *c = nullptr;
QString s ("some text");
c = s.toAscii().data();
//work with c
 

Так делать нельзя. toAscii возвращает временный объект QByteArray, у него ты получаешь указатель на внутренние данные, но на следующей же строчке этот объект будет разрушен и твой указатель будет указывать на какую-то ячейку памяти с мусором. В большинстве случаев, если сразу читать оттуда данные, все будет корректно, но вообще там может быть все, что угодно. Не делай так. Если хочется именно char*, то корректно будет:
Код
C++ (Qt)
char *c = nullptr;
QString s ("some text");
const QByteArray b (s.toAscii());
c = b.data();
//work with c
 

В твоем случае char * вообще не нужен, оперируй QString'ами.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #3 : Март 02, 2017, 09:17 »

Код
C++ (Qt)
char *c = nullptr;
QString s ("some text");
const QByteArray b (s.toAscii());
c = b.data();
//work with c
 


Надо QByteArray без const либо const char *c и константную ссылку на QByteArray  принимать вместо инициализации
« Последнее редактирование: Март 02, 2017, 09:19 от __Heaven__ » Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #4 : Март 02, 2017, 09:28 »

Это был псевдокот. Улыбающийся Чо докопался.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
__Heaven__
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2130



Просмотр профиля
« Ответ #5 : Март 02, 2017, 11:29 »

хз, настроение подокапываться Веселый
Записан
GeorgiiN
Гость
« Ответ #6 : Март 02, 2017, 12:04 »

Типичная ошибка новичков.

Код
C++ (Qt)
char *c = nullptr;
QString s ("some text");
c = s.toAscii().data();
//work with c
 

Так делать нельзя. toAscii возвращает временный объект QByteArray, у него ты получаешь указатель на внутренние данные, но на следующей же строчке этот объект будет разрушен и твой указатель будет указывать на какую-то ячейку памяти с мусором. В большинстве случаев, если сразу читать оттуда данные, все будет корректно, но вообще там может быть все, что угодно. Не делай так. Если хочется именно char*, то корректно будет:
Код
C++ (Qt)
char *c = nullptr;
QString s ("some text");
const QByteArray b (s.toAscii());
c = b.data();
//work with c
 

В твоем случае char * вообще не нужен, оперируй QString'ами.

Огромное спасибо, эту информацию я почему-то не находил (скорее всего, не вчитывался).

Дело в том, что char* мне нужны для работы функций сравнения. Я смотрю по последним и первым буквам названий городов, чтобы понять, есть такой город или нет. А как работать с буквами QString не совсем представляю, с char* хотя бы из вузовского курса все понятно и плево.

А с предложенным вариантом, получается, в моем случае для "конвертирования" данных будет корректным использовать
Код
C++ (Qt)
char *c = nullptr;
QString s ("some text");
QByteArray b (s.toAscii());
c = b.data();
//work with c
 
И моей главной ошибкой была прямая зависимость необходимого указателя от toAscii?

И еще один момент, все же. "append()" для QTextBrowser ничего не делает с принятой строкой?
Потому что, как я прикладывал к самой теме (еще раз приложу ниже конкретный) скрин, где мой "контроль качества" работал, но с добавлением строчки вывода городов на экран начинал веселиться по полной.
Цитировать

И даже если у меня были проблемы с toAscii, то несколько append подряд без каких-либо изменений (даже если не переприсваивать переменной значение) выдавал то разные, то одинаковые правильные и неправильные результаты (о коем рандоме я и говорил). Конкретнее, я говорю про строки вида:
Код
C++ (Qt)
ui->display->append();
ui->display->append();
ui->display->append();
Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #7 : Март 02, 2017, 12:10 »

Цитировать
Дело в том, что char* мне нужны для работы функций сравнения. Я смотрю по последним и первым буквам названий городов, чтобы понять, есть такой город или нет. А как работать с буквами QString не совсем представляю, с char* хотя бы из вузовского курса все понятно и плево.

Сравнение по char* - это С-стиль.
В QString имеется много возможностей для чтения символов и сравнения - left(), right(), startsWith(), endWith() и т.д.
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #8 : Март 02, 2017, 12:40 »

Забудь про char, используй возможности QString. Если чего-то не зватает, спрашивай.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
GeorgiiN
Гость
« Ответ #9 : Март 04, 2017, 21:06 »

Еще раз здравствуйте, наконец-то дорвался до программы)

Перво-наперво, хотел бы попросить модераторов перенести эту тему в раздел "для новичков", потому что QTextBrowser здесь, как выяснилось, и ни при чем. Заранее спасибо.

А теперь дальше. По вашим советам перестроил программу полностью под QString и столкнулся с новой проблемой и непониманием, а именно чтением файлов и присваиваниями QString между собой. Буду дальше задалбливать идиотскими вопросами и отвлекать от нормальной жизни, если позволите.

head:
Код
C++ (Qt)
struct names /*spisok nazvanii*/
{
   QString CityName; /*nazvanie goroda*/
   names * next; /*ukaz na sled*/
};
 
struct dict  /*slovar gorodov iz faila*/
{
   QString letter; /*bukva*/
   names name;/*spisok nazvanii na tekush bukvu*/
   int NumberOfNames; /*kol-vo zapisei v razdele nazvanii gorodov*/
   dict * next;/*ukaz na sled*/
   names * first; /*ukaz na pervuyu zapis*/
};

Чтение файла с городами, формирование словаря:
Код
C++ (Qt)
dict * firstDict=NULL;/*nachalo*/
   names * firstNames=NULL; /*nachalo spiska nazvanii*/
   dict * currDict; /*ukaz dlya perebora spiska*/
   names * currNames; /*ukaz dlya perebora nazvanii*/
   int Number,x;
 
 
   QFile file(":/files/Logos/List.txt");
   if (!file.open(QFile::ReadOnly | QFile::Text))
   {
       QMessageBox::warning(this,tr("Error"),tr("Unreal to read this directory"));
       return 0;
   }
   else
   {
       ui->display->append("Begin");
       QString bufChar = "\0", bufName;/*buffer dlya obmena*/
       QTextStream in(&file);
       in.setCodec("windows-1251");
       while(!in.atEnd())
       {
           bufName = in.readLine(30);
           x=QString::compare(QString(bufName[0]),bufChar);
           if (x!=0)/*novaya bukva nachala nazvanii*/
           {
               bufChar=QString(bufName[0]);
               ui->display->append(bufChar);
               currDict=(dict *)malloc (sizeof(dict));/*videlenie pamyati*/
               currDict->next = firstDict;
               //!!currDict->letter=bufChar;/*zapis pervoi bukvi*/
               firstNames=NULL;/*novii spisok gorodov*/
               currDict->first=(names *)malloc (sizeof(names));/*videl pamyati dlya novoi zapisi v spiske gorodov*/;
               firstDict=currDict;/*sform pervii element v slovare*/
               currNames=currDict->first;
               //!!currNames->CityName=bufName;/*zapis nazvaniya*/
               currNames->next = NULL;
               firstNames=currNames;
               Number=0;
               currDict->NumberOfNames=++Number;
           }
           else /*takaya bukva uje imeetsya*/
           {
               currDict->first=(names *)malloc (sizeof(names));
               currNames=currDict->first;
               currNames->next = firstNames;
               //!!currNames->CityName=bufName;/
               currDict->NumberOfNames=++Number;
               firstNames=currNames;
           }
       }
       file.close();
   }

Проблема: не могу понять, почему программа вылетает, если я убираю любое из трех "//!!" (помечены комментариями в коде). Я присваиваю QString'у QString, и программа после этого вылетает. Конечно, это может быть взаимосвязано, но тогда не понятно, почему не хочет работать самая первая строчка "currDict->letter=bufChar;", где letter - QString и bufChar - QString(QString[]). Пробовал вместо QString[0] использовать QString.mid(0,1) - то же самое. Прошу объяснения глупцу, где я заставляю ваши глаза кровоточить!
Записан
GeorgiiN
Гость
« Ответ #10 : Март 04, 2017, 22:34 »

При изменении прошлого ответа ломается код, поэтому просто добавлю второе сообщение.

Алгоритм весь работает. Первую букву выводит, принимаемые города выводит корректно. Программа вылетает даже при этом виде первой "закрытой" строчки. В чем может быть проблема?
Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #11 : Март 05, 2017, 03:16 »

Вот из-за этого плохо становится:

currDict->first=(names *)malloc (sizeof(names));

зачем это надо??? зачем выделять память динамически? берем QStringList и работаем с ним как белые люди Улыбающийся
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
GeorgiiN
Гость
« Ответ #12 : Март 05, 2017, 09:00 »

Если брать QStringList, то я создам просто список городов без какой-либо сортировки. Мой алгоритм рассматривает и сравнивает первые буквы введенных городов с последними, бегает по разным структурам, которые содержат данные о городах и буквах, и, как мне кажется, с указателями в структурах очень удобно работать. Здесь не совсем понимаю, как сделать равноценную замену.
И, собственно, почему динамическое выделение памяти ломает запись QString? С char * все было прекрасно.

Попробовал 3 malloc заменить на форму dict* xxx = new dict - все равно вылетает. Не очень хочется ломать приятную структуру :/

UPD
Переделал почти все под QStringList, все работает и не жалуется, но все еще волнует энергозатратность такого рода деятельности. Плюс мне нужны кол-ва городов на каждую букву, а для этого придется создавать 2 массива еще дополнительных, один с буквами, а другой с цифрами - какой-то бред. Количества городов я использую в формуле подсчета очков и в формуле "ответа" компьютера городами.

Поэтому, все же, очень хотел бы узнать, как можно организовать рабочие структуры, если это возможно.
« Последнее редактирование: Март 05, 2017, 23:55 от GeorgiiN » Записан
Racheengel
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2679


Я работал с дискетам 5.25 :(


Просмотр профиля
« Ответ #13 : Март 06, 2017, 01:37 »

Поиск городов лучше через QMultiMap сделать. Буква-ключ, город-значение.
Для подобной задачи "энергозатратность" через Qt-классы будет заметно ниже, чем через поинтеры и структуры Улыбающийся
Записан

What is the 11 in the C++11? It’s the number of feet they glued to C++ trying to obtain a better octopus.

COVID не волк, в лес не уйдёт
GeorgiiN
Гость
« Ответ #14 : Март 06, 2017, 08:40 »

Хм, спасибо, разберусь с этим.
А как быть с количеством городов на каждую букву? Раньше у меня функция ответа компьютера своим городом на последнюю букву твоего рандомила число в пределах кол-ва городов на необходимую букву и брала необходимое из списка городов на эту букву. Здесь же у меня сплошной список. Придется каждый раз высчитывать кол-во городов на более ранние буквы?


И еще один идеологический вопрос. Если я не нажимаю кнопку "сдаться", которая завершает работу игры, а нажимаю на красный крестик приложения, как обыкновенный стандартно мыслящий юзер, то программа у меня начинает бесконечно спавнить QMessageBox'ы с ошибками, которые прописаны внутри программы. То есть, есть проверка на выход, и если делать по-человечески - то ошибок не возникает и все замечательно, но если сделать вылет из приложения, то у меня начинает вылезать бесконечная ошибка, отладчик на начальных этапах из меня божеский.  Веселый
Можно ли как-то поработать с кнопкой закрытия приложения, или как вообще такое отследить?
« Последнее редактирование: Март 06, 2017, 11:40 от GeorgiiN » Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.289 секунд. Запросов: 22.