Страницы

Поиск по вопросам

Показаны сообщения с ярлыком gui. Показать все сообщения
Показаны сообщения с ярлыком gui. Показать все сообщения

пятница, 13 марта 2020 г.

Снятие фокуса с кнопки

#cpp #qt #gui #qt5


Как снять фокус с кнопки при нажатии на пустую область формы(область формы, где нет
ни одного виджета)?
    


Ответы

Ответ 1



В обработчике нажатия на форму напишите setFocus();, или, если это QMainWindow наследник, тогда centralWidget()->setFocus();. Таким образом фокус перейдёт с кнопки на виджет. Например, это можно сделать так: void MainWindow::mousePressEvent(QMouseEvent *) { centralWidget()->setFocus(); } Т.е. Вы переопределяете виртуальную функцию mousePressEvent в Вашем QMainWindow

пятница, 28 февраля 2020 г.

Разработка аналога regedit в Windows [закрыт]

#c_sharp #cpp #windows #gui


        
             
                
                    
                        
                            Закрыт. Данный вопрос необходимо конкретизировать. Ответы
на него в данный момент не принимаются.
                            
                        
                    
                
                            
                                
                
                        
                            
                        
                    
                        
                            Хотите улучшить этот вопрос? Переформулируйте вопрос,
чтобы он был сосредоточен только на одной проблеме, отредактировав его.
                        
                        Закрыт 2 года назад.
                                                                                
           
                
        
Нужно написать аналог утилиты regedit для работы с реестром Windows для курсовой
на c++, можно и на c#. Хотелось бы уточнить, насколько вообще это задание сложное?
Какие библиотеки можно использовать для этого? С помощью каких компонентов можно создать
такой графический интерфейс (дерево каталогов и т.п.)?


    


Ответы

Ответ 1



Это Windows программа в самой простейшей вариации. В главном окне - вертикальный сплиттер, в левой панели дерево (tree control), в правой панели список (list control). Графическое оформление легко исполняется даже на чистом WinAPI, с любым фреймворком вообще без труда. Пожалуй, проще всего будет Visual C++ и MFC - в шаблонах MFC проектов есть 'Explorer', который создает это приложение полностью, останется только добавить конкретное наполнение (то есть работу с реестром). Для работы с реестром можно использовать класс CRegKey. ДОПОЛНЕНИЕ Выше произошел долгий спор на тему того, нужно ли асинхронно читать реестр для последующего отображения в treectrl и listctrl. Я считаю такую оптимизацию полной глупостью, и чтобы не быть голословным, решил написать небольшой тест, который читает основные ветки и сообщает затраченное время. Первоначальная версия с GetTickCount выдала все нули, так что пришлось переделывать ее на таймер высокого разрешения. static double frequency; void EnumReg(LPCTSTR szHiveName, HKEY hHive) { LARGE_INTEGER tm0; if (!::QueryPerformanceCounter(&tm0)) throw win_error(); TCHAR szName[MAX_PATH]; DWORD uNameLen; DWORD nKeys = 0; LONG lr; for (;;) { uNameLen = MAX_PATH; lr = ::RegEnumKeyEx(hHive, nKeys++, szName, &uNameLen, NULL, NULL, NULL, NULL); if (lr == ERROR_NO_MORE_ITEMS) break; if (lr != ERROR_SUCCESS) throw win_error(lr); } LARGE_INTEGER elaps; if (!::QueryPerformanceCounter(&elaps)) throw win_error(); elaps.QuadPart -= tm0.QuadPart; double elapsed = (double)elaps.QuadPart; elapsed *= 1.0e3; // We need milliseconds elapsed /= frequency; _tprintf(_TEXT("%s:\t%u subkeys, elapsed time %7.3fms\n"), szHiveName, nKeys, elapsed); } void main() { try { LARGE_INTEGER freq; if (!::QueryPerformanceFrequency(&freq)) throw win_error(); frequency = (double)freq.QuadPart; EnumReg(_TEXT("HKEY_LOCAL_MACHINE"), HKEY_LOCAL_MACHINE); EnumReg(_TEXT("HKEY_CURRENT_USER"), HKEY_CURRENT_USER); EnumReg(_TEXT("HKEY_CLASSES_ROOT"), HKEY_CLASSES_ROOT); } catch (generic_error &se) { printf("\n\n"); printf(se.Message()); } TCHAR pat[120]; printf("\nPress any key..."); _getts(pat); } В результате вышло следующее: Отсюда очевидно, что время наполнения и обновления контрола будет минимум на порядок превышать время чтения реестра. Это если говорить о уникально огромной ветке HKCR. Для любого другого ключа время чтения будет составлять микросекунды, так что любые многопоточные оптимизации тут будут неуместными.

среда, 26 февраля 2020 г.

Объясните критерии ТЗ

#java #javafx #gui


Пишу ТЗ. Небольшая иерархия классов с реализацией основных принципов ООП. Вот мой проект



(есть абстрактный класс electric_app.., классы наследники в пакете equipments и main
с menu)

Есть определённые критерии к проекту, которые я не понимаю, а именно:

4.Проверка работоспособности через тесты.
(Какие тесты? Как их провести и где почитать)

5.Для хранения параметров инициализации можно использовать файлы.
(В частности просили изучить MySql, с этим кое-как, думаю, разберусь, ладно)

6.Использовать механизм логгирования.
(Тут полный ноль, читал, что есть несколько фичей на этот счёт, может кто порекомендовать
что? (Почитать хотя бы))

7.Использовать библиотеки сборки.
(??? Имеется ввиду задействовать библеотеки java или чьи-то другие или что?)

8.Неформально предложили сделать какой-то GUI, но я вообще тут не шарю. В универе
только консольные приложения на c++ и c# писал.
Читал про swing, но говорят, что он устарел и тот же javafx гораздо "богаче".
javafx? хмм, что-то пытался, но как-то находил только ссылки, где показывали как
кнопку одну добавить. Да и после android studio и windows forms(.net) вручную всё описывать
слегка непривычно. Может кто-что посоветовать?
    


Ответы

Ответ 1



далее идет 100% IMHO 4.Проверка работоспособности через тесты. (Какие тесты? Как их провести и где почитать) Имеются ввиду unit-тесты, это такие маленькие программы, которые всячески используют ваш код и проверяют результаты на корректность. Для этого существуют специальные библиотеки (junit, mockito). Необходимость юнит-тестов, даже если для вас пока она для вас туманна, очень большая. Они по факту являются контрактом к вашему коду, и помогают понять что-вы что-то сломали, если их постоянно прогонять перед компиляцией. Писать код, который легко покрыть тестами весьма непросто, и по началу вам не будет хотеться их писать. 6.Использовать механизм логгирования. (Тут полный ноль, читал, что есть несколько фичей на этот счёт, может кто порекомендовать что? (Почитать хотя бы)) Логгирование - это запись информации о работе приложения в постоянное хранилище(файл, база данных, облако, /dev/null). Вы можете это делать и руками, но для этого существует множество решений. немного истории и сравнение логгеров. 7.Использовать библиотеки сборки. (??? Имеется ввиду задействовать библеотеки java или чьи-то другие или что?) Это такие специальные средства, которые автоматизируют рутинную работу программиста, вроде менеджмента зависимостей и запуска компилятора с необходимыми условиями, unit-тестов итд. С ними от написания кода, до получения готового приложения для поставки нужна одна команда и все. статья про maven на хабре статья про gradle на хабре 8.Неформально предложили сделать какой-то GUI, но я вообще тут не шарю. В универе только консольные приложения на c++ и c# писал. Читал про swing, но говорят, что он устарел и тот же javafx гораздо "богаче". javafx? хмм, что-то пытался, но как-то находил только ссылки, где показывали как кнопку одну добавить. Да и после android studio и windows forms(.net) вручную всё описывать слегка непривычно. Может кто-что посоветовать? Swing устарел, но не сломался, на нем по прежнему можно написать gui, по нему много туториалов в интернете и ответов на этом ресурсе. Для учебного задания он отлично подойдет, хоть он и не торт. JavaFX - новая штука, но попробовать её в реальном деле, в отличие от swing, мне не довелось. Только один компонент - WebView. С ним все прекрасно - показывает веб странички. Графика это отдельная очень обширная тема, рисовать можно и при помощи видеокарты, но на данной стадии это только все усложнит.

вторник, 25 февраля 2020 г.

GUI для консольного приложения (выполнение команд после запуска)

#c_sharp #gui #console #execute


Добрый день. 
Столкнулся с такой проблемой, решил создать GUI для консольного приложения, запускаю
его так.
MyProc.StartInfo.FileName = filename;
MyProc.StartInfo.Arguments = arguments;
MyProc.StartInfo.UseShellExecute = false;
MyProc.StartInfo.RedirectStandardOutput = true;
MyProc.Start();
if (waitforexit)
    MyProc.WaitForExit();

Запускается приложение с ключом без проблем, но как передать этому приложению ещё
одну команду? Запускать заново - не вариант, т.к приложение запускается таким образом
cProgram.exe file_name

И дальше идет выполнение команд внутри cProgram
(cProgram) write_some_comand

Как быть?    


Ответы

Ответ 1



Обмениваться с приложением через пайп. Вот пример (delphi): консольный редирект в обе стороны. Еще лучше пример тут: Creating a Child Process with Redirected Input and Output. Но это WinAPI.

Ответ 2



Послать в консоль команду: myProc.StandardInput.WriteLine("write_some_comand\r\n"); myProc.StandardInput.Flush(); Можно также создать процесс, не показывая самой консоли: myProc.StartInfo.CreateNoWindow = true; myProc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;

Ответ 3



Что-то мне подсказывает winapi (sendmessage, postmessage). Общий алгоритм таков: ищете название окна (тоже winapi FindWindow), получаете handle окна и по это handle отправляете message (можно стандартные, WM_CLOSE, etc.). Или же делаете свой, кастомный message-list-parameters.

Intellij IDEA: создать GUI приложение

#java #intellij_idea #gui


Как в этой замечательной среде создать GUI приложение?
Я что-то не могу найти там кнопки/ползунка и т.д. как это есть в том же Xcode/Visual
Studio. Или IDEA не даёт такой возможности?
    


Ответы

Ответ 1



В проекте на пакете нажимаете правой кнопкой миши "New" -> "GUI Form".

понедельник, 24 февраля 2020 г.

Разместить окно приложения по заданным координатам

#python #gui


Есть окно определенного приложения, хочу с помощью питона управлять расположением
окна на экране. Т.е. задавать координаты, и окно будет перемещено согласно координатам.
Как это можно сделать ?
    


Ответы

Ответ 1



Напрямую - никак. Нужно искать соответствующие API операционной системы и графической оболочки и биндинги для них к Python. Более того - их готовых может и не оказаться. Что делать? Готовить велосипед самому. Варианты вызова Win32API описаны, например, здесь. Для X11 примеры посмотрите тут Еще нужно учесть, что просто так нормальная графическая среда не даст управлять чужими окнами - ишь чего захотели. Это как минимум серьезная дыра безопасности. чужими - подразумеваю: созданными не Вашим конкретным приложением. В это входят и окна приложений, запущенных другими пользователями в т.ч.

суббота, 22 февраля 2020 г.

Несколько вопросов по XAML (C#)

#c_sharp #wpf #xaml #gui


Написал интерфейс в XAML. До этого пользовался только Windows Form.

Возникло несколько вопросов:


Как сглаживать изображения? На скриншоте может не особо заметно, но картинки выглядят
угловато и это не очень то и красиво.
Кнопки тут у меня, в отличии от WinForm, почему-то выглядят не очень симпатично.
Как убрать стрелку для элементов не влезающих в тулбар?
Как растянуть объект по оставшемуся свободному месту независимо от содержимого. Конкретно
TextBox не принимает значение ширины "*" или
"Star".


Если вы найдёте в коде ещё какие недочёты, то буду благодарен совету о том, как их
исправить. Ибо первый раз работаю и много не знаю.

P.S. Учебник по WPF читаю, но программу надо бы сделать чем раньше, тем лучше, поэтому
ждать пока дочитаю и во всём разберусь ждать не приходится.





    
        
            
                
                    
                        
                    
                
                
                
                    
                        
                    
                
            
            
            
            
        
        
            
                
                
                    
                    
                    
                    
                        
                            
                            
                            
                            
                        

                        
                            
                            
                        

                        
                        
                            
                            
                            
                            
                            
                        

                        
                        
                            
                            
                        

                        
                        

                        
                        
                    
                
            
            
            
                


Ответы

Ответ 1



Сглаживать растровые изображения не нужно. Либо используйте изображение в нативном размере (вот тут много хороших советов), либо переходите наконец на современные технологии и используйте векторные изображения. Кнопки в WPF стилизуются в зависимости от операционной системы. Попробуйте запустить ту же программу на старой системе, думаю, что будет выглядеть так, как вы хотите. Убрать overflow grip проще всего, отредактировав шаблон (правая кнопка мыши в визуальном редакторе в Visual Studio 2015+), есть решение с code-behind здесь. Если вам нужен Toolbar без overflow и с кастомным лэйаутом, используйте вместо него просто DockPanel. Теперь по коду: Вы не используете MVVM. У вас данные жёстко прописаны в UI. Это неправильно, нужно отделять контент от представления и брать данные из VM. Например, список статусов и возможные оценки — точно не сфера компетенции UI. Заодно и код получится проще: и исчезнет дубляж списка оценок. Grid с семью строками и шестью столбцами кажется неоправданно сложным. Я бы поместил Main title name и Second title name в StackPanel или там DockPanel вместе с остатком, а остаток (Эпизодов/Статус/Оценка) положил в Grid с двумя столбцами и тремя строками. Ну и поскольку всего на странице много, я бы разбил на маленькие осмысленные UserControl'ы.

воскресенье, 16 февраля 2020 г.

Несколько вопросов по XAML (C#)

#c_sharp #wpf #xaml #gui


Написал интерфейс в XAML. До этого пользовался только Windows Form.

Возникло несколько вопросов:


Как сглаживать изображения? На скриншоте может не особо заметно, но картинки выглядят
угловато и это не очень то и красиво.
Кнопки тут у меня, в отличии от WinForm, почему-то выглядят не очень симпатично.
Как убрать стрелку для элементов не влезающих в тулбар?
Как растянуть объект по оставшемуся свободному месту независимо от содержимого. Конкретно
TextBox не принимает значение ширины "*" или
"Star".


Если вы найдёте в коде ещё какие недочёты, то буду благодарен совету о том, как их
исправить. Ибо первый раз работаю и много не знаю.

P.S. Учебник по WPF читаю, но программу надо бы сделать чем раньше, тем лучше, поэтому
ждать пока дочитаю и во всём разберусь ждать не приходится.





    
        
            
                
                    
                        
                    
                
                
                
                    
                        
                    
                
            
            
            
            
        
        
            
                
                
                    
                    
                    
                    
                        
                            
                            
                            
                            
                        

                        
                            
                            
                        

                        
                        
                            
                            
                            
                            
                            
                        

                        
                        
                            
                            
                        

                        
                        

                        
                        
                    
                
            
            
            
                


Ответы

Ответ 1



Сглаживать растровые изображения не нужно. Либо используйте изображение в нативном размере (вот тут много хороших советов), либо переходите наконец на современные технологии и используйте векторные изображения. Кнопки в WPF стилизуются в зависимости от операционной системы. Попробуйте запустить ту же программу на старой системе, думаю, что будет выглядеть так, как вы хотите. Убрать overflow grip проще всего, отредактировав шаблон (правая кнопка мыши в визуальном редакторе в Visual Studio 2015+), есть решение с code-behind здесь. Если вам нужен Toolbar без overflow и с кастомным лэйаутом, используйте вместо него просто DockPanel. Теперь по коду: Вы не используете MVVM. У вас данные жёстко прописаны в UI. Это неправильно, нужно отделять контент от представления и брать данные из VM. Например, список статусов и возможные оценки — точно не сфера компетенции UI. Заодно и код получится проще: и исчезнет дубляж списка оценок. Grid с семью строками и шестью столбцами кажется неоправданно сложным. Я бы поместил Main title name и Second title name в StackPanel или там DockPanel вместе с остатком, а остаток (Эпизодов/Статус/Оценка) положил в Grid с двумя столбцами и тремя строками. Ну и поскольку всего на странице много, я бы разбил на маленькие осмысленные UserControl'ы.

среда, 5 февраля 2020 г.

Git GUI - Переключение между ветками с удалением и восстановлением файлов

#git #gui #git_branch


Можно, конечно, и объяснением через командную строку, но желательно через Git GUI
(а иначе зачем создавать gui-клиент, который не может того, что может консоль).

Суть в том, что у разных веток разное количество файлов. И часть из файлов используется
'вручную'. В общем, мне нужно, чтобы при переключении с Ветки1 на Ветку2 удалялись
файлы, не используемые Веткой2 и создавались те, что используются ей. Такое возможно?

Да, я мог бы спросить об этом у создателей программы, но здесь есть шанс на более
быстрый ответ, да и, как я и сказал, меня устроит и решение через консоль.
    


Ответы

Ответ 1



В общем, мне нужно, чтобы при переключении с Ветки1 на Ветку2 удалялись файлы, не используемые Веткой2 и создавались те, что используются ей. В целом так и происходит. Давайте для начала разберёмся с терминологией, чтобы точно понимать друг друга. Ветка - это всего лишь легковесный указатель на коммит. Она реализована просто как файл, а в файле лежит номер (SHA-1) коммита. Переключаясь на другую ветку вы на самом деле переключаетесь на другой коммит. Файлы и папки не используются веткой или коммитом. Правильнее говорить, что файл (или конкретное состояние файла) принадлежит коммиту или сохранено в коммите. Коммит внутри себя содержит структуру файлов и папок, которые в нём были сохранены, в том числе содержимое файлов. По своей сути это такая "фотография" рабочей области вашего проекта. При переключении на другой коммит происходит перестроение всех файлов и папок на то состояние, которое сохранено в том коммите. Давайте представим, что у нас есть две ветки: master и feature и рассмотрим различные ситуации. Здесь буквы - это разные коммиты. D feature / A--B--C/--E master* Мы находимся в master и переключаемся на feature: git checkout feature Пусть у нас есть некоторый файл. Обозначим его содержимое в коммитах C, D, E, в рабочей области проекта (working tree, wt) и результат checkout'a (или его попытки). x - файл удалён 1, 2, 3 - различные варианты содержимого | C | E | D | wt | Результат --------------------------------------------------------------------- | 1 | 1 | 1 | 1 | 1, без изменений | 1 | 1 | 1 | 2 | 2, несохранённое изменение останется | 1 | 1 | 3 | 1 | 3, терять нечего, содержимое просто меняется | 1 | 2 | 1 | 2 | 1, аналогично | 1 | 2 | 3 | 2 | 3, аналогично. # итог: если последнее состояние файла закоммичено (E == wt), # конфликтов никогда не будет | 1 | 1 | 2 | 3 | Fail, будет потеря несохранённых изменений | 1 | 2 | 2 | 3 | 3, git распознаёт, что изменения в коммитах одинаковы. | 1 | 2 | 3 | 3 | Fail. Текущее состояние файла равно сохранённому в D, # но с точки зрения текущего коммита это потеря несохранённых изменений. | 1 | 2 | 1 | 3 | Fail. Даже если файл менялся только в одном коммите, # нельзя применить изменение "2" -> "3" к содержимому "1" # теперь поудаляем. | C | E | D | wt | Результат --------------------------------------------------------------------- | 1 | x | 1 | x | 1. Файл восстановлен, как раз то что вам нужно. | 1 | 1 | x | 1 | x. В той ветке файл удалён. | 1 | 1 | x | 2 | Fail, потеря изменений. | 1 | 1 | 2 | x | Fail, удаление - это тоже изменение. | 1 | 1 | 1 | x | x, изменение есть, но конфликта нет. # Файл независимо появился в разных ветках | x | 1 | 1 | 1 | 1, всё нормально | x | 1 | 2 | 1 | 2, даже если содержимое разное | x | 1 | 2 | 2 | Fail, снова потеря, хоть содержимое и совпадает. Итого, результат checkout для каждого файла можно описать таким псевдокодом: if (E == wt) { // Если нет несохранённых изменений, берём содержимое из D return D } else if (E == D) { // Если содержимое не менялось (или менялось одинаково), // То можно оставить текущее содержимое файла return wt } else { // Иначе вероятна потеря данных fail() } Что можно делать с несохранёнными изменениями: Закоммитить Сложить в карман. Отменить с помощью git reset --hard -- filename - в одном файле git reset --hard - отменить все изменения версионируемых (отслеживаемых) файлов git clean -f - вообще почистить рабочую область, в том числе удалить неверсионируемые файлы. C -fx удалит ещё и игнорируемые файлы, с -fd захватит директории, а не только файлы. Вариант -fdx - выжигание напалмом всего, что не прибито гвоздями.

Ответ 2



При git checkout %branch_name% состояние отслеживаемых файлов в репозитории меняется в состояние крайнего коммита этого бранча (т.е. лишние файлы скроются, а нужные - добавятся). Модифицированные и новые (не зафиксированные) файлы остаются висеть. Чтобы очистить репозиторий от неотслеживаемых папок и файлов можно также выполнить git clean -dfx.

Ответ 3



если файлы 'вручную' не закомичены и не лежат в индексе в ветке1, то для их сохранения необходимо положить их 'на полку до востребования' командой git stash save --include-untracked "имя полки" После этого переключиться на ветку2 Для просмотра всех стешей надо использовать git stash list Для извлечения файлов нужно выполнить git stash apply "stash@{0}" Нужно использовать нужный индекс Аналогичен переход с ветки2

воскресенье, 2 февраля 2020 г.

Мультизадачность на Python: выполнить две долгие функции одновременно, не блокируя GUI

#python #многопоточность #gui #tkinter


Всем доброго времени суток.
Изучаю возможности графического модуля tkinter на Python. Возникла необходимость
одновременного запуска нескольких функций, т.е. имеется, например, две кнопки, каждая
со своим функционалом. Нужно сделать так, чтобы окно с кнопками после нажатия на одну
из них не зависало и позволяло нажать другую кнопку, незамедлительно запустив ее функцию.
Пишу на питоне версии 3.5.2.

from tkinter import *

def whilefunc1():
    n = 1
    while (n <= 100000):
        print(n)
        n = n + 1

def whilefunc2():
    n = 100001
    while (n <= 200000):
        print(n)
        n = n + 1

root = Tk()
root.geometry("200x200")

but1 = Button(root, text="press me", command = whilefunc1)
but1.pack() 
but2 = Button(root, text="me 2!!", command = whilefunc2)
but2.pack()

root.mainloop()

    


Ответы

Ответ 1



Общая особенность GUI программирования в том, что не следует использовать блокирующие функции в обработчиках событий, которые выполняются как правило в GUI потоке, иначе это приводит к "подвисанию" GUI. В вашем случае вместо self.status[ip] = os.system(f'ping {ip}') можно использовать self.process[ip] = subprocess.Popen(['ping', ip]) и позже проверять статус используя self.process[ip].poll() (оба вызова возвращаются сразу, не дожидаясь пока команда завершится). Периодический опрос можно организовать используя root.after(), например как в start_process(). Можно избежать опроса, если настроить обработчик сигнала, который вызывается когда запущенный дочерний процесс завершается, например, на Unix (усложнённая опция в данном случае). Cross-platform пример кода это QProcess.finished сигнал из Qt GUI библиотеки, который позволяет подключить свой обработчик, который вызывается, когда команда, запущенная QProcess::start, завершается (finished сигнал реализован эффективно, используя функциональность, предоставляемую соответствующей операционной системой, не требуя периодического опроса статуса запущенного дочернего процесса). Альтернативно, если необходимо запустить числодробительную задачу (CPU-bound), то для этого можно создать пул процессов: from concurrent.futures import ProcessPoolExecutor pool = ProcessPoolExecutor() и использовать command=lambda: pool.submit(whilefunc1) в качестве обработчика событий для кнопки (.submit() ставит выполнение whilefunc1() функции в очередь и сразу же возвращается). Если вы нажмёте 1000 раз на кнопку, то вы скорее всего не хотите запускать 1000 процессов (системе вероятно плохо будет). ProcessPoolExecutor() по умолчанию использует все доступные CPU ядра, не запуская излишние процессы. В этом смысле, это решение более предпочтительно чем решения, использующие threading.Thread(..).start() или multiprocessing.Process(..).start(), где каждое нажатие на кнопку приводит к запуску нового потока/процесса. Если задача связана с вводом-выводом, то можно использовать Widget.tk.createfilehandler() или аналогичную функциональность в других GUI библиотеках (например, GObject.io_add_watch()). Вот пример кода, где root.createfilehandler() используется чтобы читать вывод внешней команды, не дожидаясь её завершения. Поддержка createfilehandler() может быть ограничена на некоторых платформах (Windows), поэтому ту же задачу можно переносимо выполнить используя фоновый поток (попытка использовать socketpair, чтобы получить переносимый код, оказалась неуспешной: Popen() не принимает соответствующий fileno() на Windows).

Ответ 2



Можно сделать декоратор def thread(fn): def execute(*args, **kwargs): threading.Thread(target=fn, args=args, kwargs=kwargs).start() return execute тогда можно вынести(@thread) выполнение функции в отдельный поток, без изменения остального кода @thread def whilefunc1(): # эта функция всегда будет вызватся в отдельном потоке n = 1 while (n <= 100000): print(n) n = n + 1 but1 = Button(root, text="press me", command = whilefunc1) если выполнение в потоке всегда, ненужно, то задекорировать можно и так def whilefunc2(): n = 100001 while (n <= 200000): print(n) n = n + 1 but2 = Button(root, text="me 2!!", command = thread(whilefunc2)) это избавляет от постоянного объявления threading.Thread

Ответ 3



Ну в общем-то нашел решение: Изменил but1 = Button(root, text="press me", command = whilefunc1) but1.pack() but2 = Button(root, text="me 2!!", command = whilefunc2) but2.pack() на but1 = Button(root, text="press me", command = lambda: threading.Thread(target = whilefunc1).start()) but1.pack() but2 = Button(root, text="me 2!!", command = lambda: threading.Thread(target = whilefunc2).start()) but2.pack() Однако я до сих пор не понимаю зачем там нужна lambda:, однако без нее не работает

суббота, 1 февраля 2020 г.

Можно ли сделать исполняемый файл приложения, написанного на java с расширением не jar, а exe?

#java #javafx #gui #jar #exe


Я создал приложение на языке java, но проблема в том, что после создания исполняемого
jar файла, я могу его запустить только со специальным программным обеспечением, соответственно
если кто-то попытается его запустить с другого компьютера, у него ничего не выйдет.
Как сделать исполняемый файл с расширением exe?
    


Ответы

Ответ 1



Для того, чтобы преобразовать jar в exe, нужно скачать Launch4j, установить путь к начальному файлу и конечному результату (с нужным расширением) Нажать на вкладку JRE, в пункте Min JRE version написать 1.6.0_22 После чего нажать на шестерёнку, вбить имя доп файла и нажать save

Ответ 2



Если вы используете IntelliJ тогда в Project Structure -> Artifacts -> выберите Native Bundle: All далее выберите во вкладке Build -> Build Artifact -> имя приложения -> Build *.exe файл вы найдете тут: USER\IdeaProjects\projectname\out\artifacts\projectname\bundles\projectname -> там будет находится ваш .exe файл.

вторник, 28 января 2020 г.

Как рисовать 2D пользовательский интерфейс в игре поверх 3D?

#java #opengl #разработка_игр #gui #lwjgl


Я создал 3D игру наподобие Minecraft на языке Java при помощи библиотеки LWJGL. Так
же могу передвигаться по миру, смотреть вверх, вниз, оглядываться, и так далее. А как
отобразить панель, наподобие той, которую я выделил красным цветом на прикреплённом
рисунке? 



Допустим, эти квадратики я нарисовал в Paint'е и сохранил в файле panel.png, но как
её отобразить?

Напишите примерный исходный код.
    


Ответы

Ответ 1



В коде инициализации экрана (перед главным циклом) написать следующий код: GL11.glEnable(GL11.GL_TEXTURE_2D); GL11.glEnable(GL11.GL_BLEND); GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); GL11.glMatrixMode(GL11.GL_MODELVIEW); GL11.glMatrixMode(GL11.GL_PROJECTION); GL11.glLoadIdentity(); GL11.glOrtho(0, Display.getWidth(), Display.getHeight(), 0, 1, -1); GL11.glMatrixMode(GL11.GL_MODELVIEW); Texture i4 = TextureLoader.getTexture("PNG", new FileInputStream("textures" + File.separator + "myTexture.png")); А в главном цикле следующее: while (!Display.isCloseRequested()) { GL11.glClear(GL11.GL_COLOR_BUFFER_BIT); i4.bind(); GL11.glBegin(GL11.GL_QUADS); // Координаты и разрешение текстуры GL11.glTexCoord2f(0F, 0F); GL11.glVertex2f(100F, 100F); GL11.glTexCoord2f(1F, 0F); GL11.glVertex2f(100F + (float) i4.getTextureWidth(), 100F); GL11.glTexCoord2f(1F, 1F); GL11.glVertex2f(100F + (float) i4.getTextureWidth(), 100F + (float) i4.getTextureHeight()); GL11.glTexCoord2f(0F, 1F); GL11.glVertex2f(100F, 100F + (float) i4.getTextureHeight()); GL11.glEnd(); }

Ответ 2



Создайте отдельный контейнер для спрайтов, закреплённый относительно камеры и разместите в нём спрайты пользовательского интерфейса. В качестве контейнера можно использовать поростой прямоугольник с текстурой (канвой). С текстурой (канвой) можно оперировать через PixelWriter и PixelReader, перерисовывая области на плоскости. Либо можно сделать аналог Group из JavaFX, так же закрепить его экземпляр относительно камеры и уже добавлять 3D элементы интерфейса. UPD: Посмотрите обсуждение здесь https://github.com/LWJGL/lwjgl3/issues/101 UPD2: Вот здесь вопрос уже обсуждался https://gamedev.stackexchange.com/questions/18468/making-a-hud-gui-with-opengl-lwjgl (Кратко: человек отрисовывает мир, а потом уже интерфейс поверх мира только и всего). UPD3: И ещё одна рекомендация здесь https://gamedev.stackexchange.com/a/29284 - использовать готовую библиотеку для GUI в LWJGL - Nifty (http://void256.github.io/blog/ -> https://github.com/nifty-gui/nifty-gui)

Ответ 3



В общем подход такой: Рисуем игру в объемной проекции (перспектива и т.п.) Переключаем проекцию на ортографическую Выключаем буфер глубины Рисуем интерфейс

Ответ 4



В андроиде есть FrameLayout для отображения одного контента поверх второго, думаю такая штука есть и в вашей отрасли

четверг, 23 января 2020 г.

Вытягивания виджетов

#cpp #qt #gui #qt5 #интерфейс


Я работаю в qt5. Эта кнопка("addButton")  отвечает за создание этих кнопок("GreenButton")
. В слоте addButton создается GreenButton:

void SearchForm::on_AddButtonButton_pressed()
{
     Editor.pobj = new GreenButton(this);
}


Код GreenButton:

QPoint delta;

    void mousePressEvent(QMouseEvent* e)
        {
            delta.rx()   = e->pos().x();
            delta.ry()   = e->pos().y();
        }

        void mouseMoveEvent(QMouseEvent* e)
        {

            setGeometry(
                    geometry().x()  + e->pos().x() - delta.x(),
                    geometry().y()  + e->pos().y() - delta.y(),
                    width(),
                    height()
            );
        }

        explicit GreenButton(QWidget *parent = 0 ) 
        {


            setGeometry(QCursor::pos().x() - parent->geometry().x() - 8,
                        QCursor::pos().y() - parent->geometry().y() - 8,
                        111,
                        111
            );
            show();
            QMouseEvent event1(QEvent::MouseButtonPress,  this->pos(), Qt::LeftButton,Qt::LeftButton,Qt::NoModifier);

            QApplication::sendEvent(this, &event1);
        }


GreenButton создается , перемещается мышью. Как сделать чтобы при нажатии на addButton
и не отпускании ее перемещался GreenButton?
Я думал поможет искуственное создание событий, но не помогло:

QMouseEvent event1(QEvent::MouseButtonPress,  this->pos(), Qt::LeftButton,Qt::LeftButton,Qt::NoModifier);
QApplication::sendEvent(this, &event1);

    


Ответы

Ответ 1



Т.к. у нас есть форма, на которой размещена «добавляющая кнопка», и на ту же форму мы добавляем другие кнопки, предлагаю воспользоваться следующей стратегией: Устанавливаем фильтр сообщений на нашу «добавляющую» кнопку. Будем ловить нажатие и перемещение мыши. Во время нажатия будем создавать новую кнопку и запоминать её. Во время появления события перемещения, будем перемещать нашу кнопку. Всё это довольно просто реализовать: MainWindow.h: #pragma once #include class QPushButton; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget* parent = 0); bool eventFilter(QObject* obj, QEvent* event); private: QPushButton* m_CurrentButton; }; MainWindow.cpp: #include #include #include #include #include "mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { auto widget = new QWidget(this); auto addButton = new QPushButton("add", widget); setCentralWidget(widget); addButton->installEventFilter(this); } bool MainWindow::eventFilter(QObject* obj, QEvent* event) { if (event->type() == QEvent::MouseButtonPress) { auto mouseEvent = static_cast(event); m_CurrentButton = new QPushButton("new", centralWidget()); auto localPoint = mapFromGlobal(mouseEvent->globalPos()); m_CurrentButton->move(localPoint); m_CurrentButton->show(); return true; } if(event->type() == QEvent::MouseMove) { auto mouseEvent = static_cast(event); auto localPoint = mapFromGlobal(mouseEvent->globalPos()); m_CurrentButton->move(localPoint); return true; } return QObject::eventFilter(obj, event); } На базе этого кода, Вы можете адаптировать свой код.

Ответ 2



Сначала решение: class MyForm: public QWidget { QTimer * Ticker ; QPushButton * MovingButton; public: MyForm(QWidget * parent = nullptr) : QWidget (parent ) , Ticker (nullptr) , MovingButton(nullptr) { Ticker = new QTimer(this); connect(Ticker, &QTimer::timeout, this, &MyForm::moveButton); } ~MyForm() { stopMoving(); } public slots: void addPressed() { MovingButton = new QPushButton(this); // настраиваем новую кнопку MovingButton->show(); // Начинаем перемещение через пол секунды Ticker->setSigngleShot(true); Ticker->setInterval(500); Ticker->start(); } void addReleased() { stopMoving(); // останавливаем движение } void moveButton() { if(MovingButton) { if(Ticker->singleShot()) // ускоряем таймер до 30 мс { Tciker->setSignleShot(false); Ticker->setInterval(30); } // двигаем кнопку MovingButton->move(MovingButton->pos() + QPoint(8,8)); } } private: void stopMoving() { MovingButton = nullptr; Ticker->stop(); } }; Здесь addPressed() и addReleased() слоты которые должны быть подключены с сигналам кнопки AddButton pressed() и released() соответственно. Работает код следующим образом: В обработчике нажатия addPressed() создаем новую кнопку и запоминаем указатель на нее в MovingButton, потом стартуем таймер Ticker на пол секунды по окончании которого выполняем перемещение. Пол секунды нужно для того чтобы была пауза перед началом движения. В обработчике таймера Ticker moveButton() ускоряем таймер до 30 мс а также перемещаем текущую кнопку MovingButton если таковая имеется. В обработчике отпускания addRelease() просто зануляем указатель на перемещаемую кнопку MovingButton и останавливаем таймер Ticker - таким образом останаваливаем движение.

Ответ 3



предложу необычный вариант: - AddButton сделать наследником от GreenButton - Как только AddButton кликнули, что означает добавление, AddButton меняет своё рисование, на рисование предка. То есть, начинает рисоваться, как GreenButton. - Новый AddButton на месте старого можно сделать как в начале таскания, так и по его окончанию - зависит от сценария

среда, 22 января 2020 г.

Логика xml-gui-атрибутов

#xml #наследование #android #gui


Казалось бы, в написании GUI с помощью XML нет ничего сложного. Ищем в Reference
классы, наследуемые от View, записываем их в иерархическом порядке, и инициализируем
нужные свойства, которые опять же прописаны в документации каждого класса.
Но, например, свойство android:layout_weight не является параметром TextView, однако
добавляется туда, если его предком является TextView.
  
  

Мой вопрос: по какому принципу происходит подобное наследование, как отличать наследуемые
параметры от ненаследуемых, и существуют ли ещё какие-нибудь неочевидные моменты в
 написании GUI с помощью XML?    


Ответы

Ответ 1



При добавлении вьюшки куда-нибудь из кода, вы используете специфичные для лэйаута LayoutParams: // грубо relativeLayout.addView(myView, new RelativeLayout.LayoutParams(...)); Т.е. кроме параметров самого view вам нужно использовать еще параметры лэйаута контейнера, в который вы его добавляете. (в случае одноаргументного addView(View view) используются дефолтные параметры) Парсер xml-ек при генерации байт-кода сделает то же самое: если вьюшка находится в RelativeLayout, в ее тэге могут быть аттрибуты для RelativeLayout.LayoutParams. Если вы их там указали - он создаст LayoutParams с вашими атрибутами, если нет - будет использовать дефолтные. Итак: Наследования никакого нет, просто логика описания лэйаутов в xml и в коде немного отличается. Все параметры LayoutParams любого ViewGroup (LinearLayout, RelativeLayout) в xml могут добавлятья в тэг наследника. Нет железного способа отличить параметры child от параметров лэйаута parent "на ходу". Но и надобности тоже нет. Параметры задокументированы (LinearLayout.LayoutParams) Выбирая лэйаут, вы решаете какую-то задачу, а значит, вы знаете, какие параметры лэйаута вы хотите использовать, вряд ли вы их спутаете с параметрами вьюшки. Через пару месяцев работы с лэйаутами вы будете знать их наизусть :)

Ответ 2



Ответ: компоненты, такие как TexView имеют свои атрибуты + атрибуты, наследуемые от лэйаутов(менеджеров компоновки) таких как LinearLayout в которых они размещены(являются дочерними по отношению к ним)

суббота, 11 января 2020 г.

Как сделать такой listbox

#c_sharp #wpf #mvvm #gui #design


Здравствуйте, подскажите пожалуйста как сделать такой listbox на wpf+mvvm?  Как вертикальную
линию я знаю как сделать, а вот с остальным вообще нет идей, так ладно сделать кастомный
контейнер, мне вот интересно как организовать бизнес модель (грубо говоря за бизнес
модель служить у нас будет list из классов структурой msg[Integer idmsg, String text,
Date prishlo, Integer idUser]) :(



UPD #1 :

Ну вот, такой у меня ItemTemplate :

    
        
            
                
                    
                        
                        
                    
                    
                        
                    
                
            
        
    
    

    


Ответы

Ответ 1



У меня получился такой вариант. VM-классы: class MessageVM : VM { public MessageVM(string text, DateTime postedAt, UserVM author) { Text = text; PostedAt = postedAt; Author = author; } public string Text { get; } public DateTime PostedAt { get; } public UserVM Author { get; } } class UserVM : VM { public UserVM(string name) { Name = name; } public string Name { get; } } XAML: Кроме того, чтобы форматирование даты соответствовало текущему языку, вам нужно в конструкторе App использовать следующее заклинание: public App() { FrameworkElement.LanguageProperty.OverrideMetadata( typeof(FrameworkElement), new FrameworkPropertyMetadata( XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag))); } Результат: Нижний круг меньше, чтобы 15 пикселей нижней части линии смогли влезть.

пятница, 10 января 2020 г.

DLang: Как правильно прилинковать GUI-библиотеку DWT?

#gui #компоновщик #d


В процессе ознакомления с D, появилось желание написать что-нибудь простенькое с
GUI. В качестве GUI-библиотеки выбрал DWT, т.к. кроссплатформенно и является биндингом
с SWT (много обучающего материала по последнему).

Проект был скачан с ГитХаба, собран и перенесен в папку C:\D\. Методом проб и ошибок
была получена работающая команда для сборки демонстрационного окошка с надписью "Hello,
DWT!" посередине:

dmd.exe "..\src\%1" -IC:\\D\\dwt\\imp ^
-JC:\\D\\dwt\\org.eclipse.swt.win32.win32.x86\\res ^
-L+C:\\D\\dwt\\lib\\ -L+org.eclipse.swt.win32.win32.x86.lib ^
-L+dwt-base.lib -L/SUBSYSTEM:windows:4 ^
-L/rc:..\res\resource.res


, что соответствует следующим параметрам в dub.json:

"importPaths": ["C:\\D\\dwt\\imp"],
"stringImportPaths": ["C:\\D\\dwt\\org.eclipse.swt.win32.win32.x86\\res"],
"lflags": ["+C:\\D\\dwt\\lib\\"
   , "+org.eclipse.swt.win32.win32.x86.lib"
   , "+dwt-base.lib", "/SUBSYSTEM:windows:4"
   , "/rc:res\\resource.res"]


Код самой программы: 

import org.eclipse.swt.all;
void main()
{
    auto display = new Display;
    auto shell = new Shell(display);
    shell.setLayout(new GridLayout(4, false));
    auto label = new Label(shell, 0);
    label.setText("Hello, DWT!");
    shell.pack();
    shell.open();
    while (!shell.isDisposed)
        if (!display.readAndDispatch())
            display.sleep();
    display.dispose();
}


И программа собирается в один в один единственный exe без зависимостей и на ура запускается
на ОС от WinXP до Windows8. Но меня терзают серьезные сомнения, что я тут наворотил
лишнего, и можно было бы как-то по-проще. 

Если кто-то разумеет в dmd или dub и в тонкостях их отношений с линковщиком, подскажите,
как в описанной ситуации поступил бы белый человек.
    


Ответы

Ответ 1



Проще будет, если библиотеку добавят в dub-репозиторий. Пока этого не случится, нужно прописывать пути самостоятельно. Шаги, которые нужно сделать. Выбираете место для библиотеки (на вашем примере, это может быть C:\D) Открываете консоль, заходите в выбранную директорию. Следуете инструкции с github: Клонируете репозиторий git clone --recursive git://github.com/d-widget-toolkit/dwt.git Появится папка C:\D\dwt с проектом и зависимостями. Заходите в эту папку cd dwt Выполняете сборку проекта rdmd build base swt. Собственно, теперь можно подключать библиотеку в свой проект. Для компиляции из командной строки нужно будет выполнить dmd main.d -IC:\D\dwt\imp -JC:\D\dwt\res -L+C:\D\dwt\lib\ "-L+org.eclipse.swt.win32.win32.x86.lib" "-L+dwt-base.lib" -L/SUBSYSTEM:WINDOWS:4.0` Именно это и написано в инструкции на гитхабе: dmd main.d -I\imp -J\res -L+\lib\ ^ "-L+org.eclipse.swt.win32.win32.x86.lib" "-L+dwt-base.lib" ^ -L/SUBSYSTEM:WINDOWS:4.0 - это путь к директории самого dwt, лезть к res в org.eclipse.swt.win32.win32.x86 не требуется, так как нужный res лежит в самой dwt. Итог у вас почти правильный. Если внимательно следовать инструкции к библиотеке, то ошибок никаких нет. Для того, чтобы в будущем не прописывать все пути/зависимости в проекте, можно сделать "пустой" проект и впоследствии просто копировать его в качестве нового. P.S. Лично я использую библиотеку DlangUI. Кроссплатформенная, с широкими возможностями, интерфейсы можно удобно собирать, используя разметку DML (похожую на QML) и др. Есть статья от автора. P.P.S. Обязательно используйте фигурные скобки во while while (!shell.isDisposed) { if (!display.readAndDispatch()) display.sleep(); } Иначе, добавив ещё какую-нибудь строку кода, можно получить некорректную логику программы.

Ищу контрол с раскрывающимеся элементами (аккордеон)

#delphi #gui #delphi_xe7


Возникла необходимость компактно разместить на форме большое количество таблиц (TstringGrid
и TValueListEditor). К ним так же можно добавить TRadioButtonGroup.

Не раз видел, как это сделано в различных программах:



Хотел сделать так же, но не смог найти информации по этому поводу.
    


Ответы

Ответ 1



Есть такой VCL контрол - называется CategoryPanelGroup

пятница, 27 декабря 2019 г.

Методологии проектирования пользовательских интерфейсов

#gui #веб_программирование


Здравствуйте, уважаемые форумчане. Подскажите, пожалуйста, существуют ли стандарты
(методологии, диаграммы и т.д.), с помощью которых можно проектировать элементы пользовательского
интерфейса?

Поясню на примере.
Предположим, мне необходимо разработать макет некоторого сайта (для краткости буду
называть его site.ru).
Я создаю макет главной страницы (например, в MS Visio) и отмечаю на нем некоторые
элементы, например, кнопку регистрации. Мне необходимо на схеме отобразить операции,
которые будут осуществляться при клике на данную кнопку.

Пусть, при клике на кнопку, выполняются следующие операции:


Отображается всплывающее окно с полями "Имя", "E-mail", "Пароль" и кнопкой "Отправить".
При заполнении полей из п.1 и клике на кнопку "Отправить" отображается сообщение
"На ваш e-mail отправлено сообщение с сылкой для подтверждения регистрации".


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

Аналогия.
В разработке программного обеспечения есть язык UML. С помощью него можно схематично
отображать элементы (не путайте с элементами пользовательского интерфейса) разрабатываемой
программы. В качестве наглядного примера привожу скрин диаграммы активности:



Хотелось бы найти похожую аналогию для элементов пользовательского интерфейса.

P.S.
Программы Axure и ей подобные не подходят. Так как, описание поведения необходимо
прикреплять к техническому заданию.

Заранее спасибо.
    


Ответы

Ответ 1



Для описания работы интерфейса можно использовать нотацию eEPC, либо тот же uml - use-case либо диаграмма деятельности.

Вопрос о создании Интерфейса для программ

#html #cpp #gui


Где-то краем уха услышал, что можно создать интерфейс для программы С++ на HTML (css+js).
Это правда? Если, да, то можете кинуть пару обучающих книг(видео)?
    


Ответы

Ответ 1



Хочу вначале уточнить, что задача распадается на две части. Первая - это непосредственно Ваша программа на C++, которая будет что-то делать и взаимодействовать с пользователем через HTML интерфейс. Для решения этой части есть билиотеки, например WT (см. ниже). Вторая часть - это это рендеринг кода HTML в красивые кнопочки, закладочки, картинки, "галочки" и другие элементы интерфейса. Это очень серьезная и объемная задача. Ей занимается целая индустрия создания браузеров. В Вашем случае подойдет либо стандартный браузер в системе пользователя, который будет направлен на локальный адрес. Либо модуль готового движка типа Gecko, или Web-kit. В любом случае выбор за вами. Библиотека WT. Ключевые возможности: Поддержка основных браузеров (Firefox/Gecko, Internet Explorer, Safari, Chrome, Konqueror и Opera), а также браузеров простого HTML (Links, Lynx). Разработка и развёртывание на Unix/GNU Linux или Microsoft Windows (Visual Studio). Идентичное поведение как при поддержке JavaScript или Ajax, так и без таковой, насколько это возможно, посредством постепенной деградации (graceful degradation) или прогрессивного расширения (progressive enhancement). Интегрированная поддержка Юникода и локализации. Эффективный рендеринг и низкая латентность. Поддержка перемещения с помощью истории браузера (кнопки "назад"/"вперёд" и закладки), лаконичные URL при доступности истории HTML5, оптимизация для поисковиков и однообразное поведение сессий простого HTML или Ajax. Настраиваемые опции отслеживания сессий, либо посредством перезаписи URL, либо с помощью использования кук. и еще много всего "вкусного"... Подробности на сайте (на русском)

четверг, 26 декабря 2019 г.

Изменения GUI из разных потоков С#

#c_sharp #многопоточность #gui


class test
{
   public List threads = new List();
    public int nThreads = 0;
    public int maxThreads = 5;

    public void DoWork(object data)
    {
        string message = (string)data;
        //MessageBox.Show(message);        


    }

    public void CreateThread(object data)
    {
        if (nThreads >= maxThreads)
            return;
        Thread newThread = new Thread(DoWork);
        threads.Add(newThread);
        newThread.IsBackground = true;
        newThread.Start(data);
        nThreads++;


    }

    public void WindUpThreads()
    {
        //MessageBox.Show("count: " + nThreads.ToString());
        for(int i = 0; i < threads.Count; i++)
        {
            if (threads[i].IsAlive == false)
            {
                threads[i].Abort();
                threads.RemoveAt(i);
               //MessageBox.Show("removing at " + i.ToString());
            }

        }

        nThreads = threads.Count;
    }

}


Мне нужно в методе DoWork изменять данные в listbox, но я не хочу привязывать логику
к элементам управления. Как лучше поступить в таком случае?

В общем я решил пойти самым простым путем и передал делегат в тред:

   public delegate void TestDeleg(string message);
public class Data
{
    public TestDeleg deleg;
    public string mess;
    }

public void DoWork(object data)
{
    Data d = (Data)data;
    d.deleg(d.mess);
    //string message = (string)data;
    //MessageBox.Show(d.mess);      
    return;


}


В цикле теперь передаю класс с запакованным данными:

Data d = new Data();
d.deleg = AddItem;
d.mess = strings[counter];
thTest.CreateThread((object)d);


Ну и сам метод, который добавляет строку в листбокс:

public void AddItem(string message)
{

    //listBox1.Items.Add(message);
    if(InvokeRequired)
        listBox1.Invoke( (Action)( () => { listBox1.Items.Add(message); } ) );
    else
        listBox1.Items.Add(message);

}


Теперь почему-то цикл никогда не заканчивается и треды не завершаются, метод, который
должен очищать треды почему-то не срабатывает.

UPD: Кажется, причина, по которой интерфейс не обновлялся, выяснилась. Основная часть
моей программы была такой:

while (flag == true)
{
    if (counter >= dataCount)
    {
        flag = false;
    }

    while (thTest.nThreads < thTest.maxThreads)
    {
        if (flag == false)
            break;

        thTest.CreateThread(strings[counter]);

        counter++;
    }

    thTest.WindUpThreads();

    if (flag == false)
    {
        do
        {
            thTest.WindUpThreads();

        } while (thTest.nThreads != 0);
    }

}


И запускался этот код по нажатию на кнопку. Получается, что цикл крутился в основном
потоке и поэтому ui не принимал сообщения об изменении. Когда я вынес уже этот код
в отдельный поток (получается один поток создает другие и управляет ими), то все стало
на свои места.
    


Ответы

Ответ 1



Нужно вашу логику отделить от представления. Представить ваше "сердце" приложения как некоторую штуку, которая принимает "команды" из UI и отправляет информацию об изменении состояния - "события". В главном потоке слушать события UI и отправлять в "сердце" соответствующие им команды; подписаться на события основной логики и в соответствий с происходящим перерисовывать ваш UI. Посмотрите на IObservable и Reactive Extensions. И общие замечания - не рекомендуется создавать потоки руками. Поток - это достаточно тяжелая сущность. Многопоточность реализуется через различные библиотеки, где примитивы несколько интереснее и более удобные, чем потоки. Куда смотреть - Rx, Task Parrallel Library; читать - Jeffrey Richter, CLR via C# последнюю редакцию, главу про многопоточность.

Ответ 2



Завести класс, хранящий состояние DoWork для отображения. Передать в DoWork делегат или объект presenter, который будет отображать состояние на listbox (используя BeginInvoke) Вызывать периодически presenter из под DoWork

Ответ 3



Как вариант, вы можете в потоках класть данные для ListBox в какую-нибудь коллекцию из System.Collections.Concurrent, а в основном (GUI) треде брать оттуда элементы и пихать их в целевой ListBox. Лично я предпочел бы использовать ConcurrentQueue следующим образом: В потоках добавляем элементы. В GUI-треде по таймеру забираем и очищаем.

Ответ 4



Мне нужно в методе DoWork изменять данные в listbox Если метод DoWork вызывается из разных потоков, то это можно проверить и данные передать в UI-поток, примерно так: public void DoWork(object data) { if (listbox.InvokeRequired) listbox.BeginInvoke(new Action(DoWork), data); else listbox.Items.Add((string)data); } На первый взгляд выглядит как рекурсия, но это не рекурсия, т.к. метод BeginInvoke ставит вызов делегата в очередь, элементы которой обрабатывается в UI-потоке. Другой пример передачи в UI-поток данных из разных потоков тут. Если надо отделить модель/данные от UI, то пример тут и тут.