Страницы

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

пятница, 30 ноября 2018 г.

Фоновый ввод информации C++

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


Ответ

Хорошо. Это решение выводит числа, пока не будет нажата какая-либо клавиша клавиатуры. В данной задаче очень полезен метод kbhit()
#include #include
using namespace std;
int main() { bool run = true; while (run) { for (int i = 1; i<1000000; i++) { if (kbhit()) { run = false; break; } cout << i << "
"; } } system("pause"); return 0; }
Если Вам необходимо, чтобы юзер ввёл именно слово "стоп", то моё решение, к сожалению, Вам категорически не подходит...

JavaFx: TreeView

Как можно сделать такие полосы (штриховку) в TreeView? Перегуглил как мог, нигде и намёка нет на подобную штуку
javafx: swing:


Ответ

Очень просто:
TreeItem item=new TreeItem(new HBox(new ImageView(new Image(inputStream)),new Label("Root"))); item.getChildren().add(new TreeItem(new HBox(new ImageView(new Image(inputStream)),new Label("Item1")))); TreeView treeView=new TreeView(item);
При желании можно сделать вместо HBox класс, который будет автоматически менять изображение в зависимости от строения TreeItem.

Регулярные выражения: из массива строк исключить подстроку

Возникла необходимость в большом куске кода внести массовую замену. Использую штатный инструмент Visual Studio 2017 и регулярные выражения для поиска. Подразумеваю, что синтаксис выражений в строке поиска соответствует синтаксису регулярных выражений в C#. Есть следующая строка
get_Label().get_UserLocalizedLabel().get_Label();
В поиске задаю выражение get_(\w*)\(\)
Получаю результат поиска:
get_Label()get_UserLocalizedLabel()get_Label()
А нужен вот такой результат:
get_Label()get_UserLocalizedLabel()get_Label()
То есть необходимо исключить слово между get_ и (). Пробовал get_(?!\w*)\(\), но не преуспел.


Ответ

Если нужно заменить get_ и () на что-то, то подойдёт такой вариант:
Find what:
get_(\w*)\(\)
Replace with:
Get$1
Для
get_Label().get_UserLocalizedLabel().get_Label()
результат:
GetLabel.GetUserLocalizedLabel.GetLabel

App.config и приложение на C#

У меня есть небольшая программа на 2 версии .NET, но новых версиях Windows она не запускается, но если создать файл настроек, то она запустится.

Есть какие-нибудь варианты, что можно сделать, чтоб было не 2 файла, а 1? Т.е внедрить этот файл настроек в exe или ещё как-нибудь.


Ответ

Встроить файл конфигурации в EXE-файл нельзя (так как весь смысл конфигурации - это возможность редактирования параметров без перекомпиляции программы, такой возможности не предусмотрели). Влиять на параметр supportedRuntime из кода на C# также нельзя, так этот параметр используется неуправляемым кодом загрузчика до того, как в процесс загружена CLR, и в этот момент управляемый код еще не может выполняться.
Если нужно управлять выбором версии CLR без файла конфигурации, единственный способ - написать свой собственный загрузчик на С++, пользуясь Unmanaged .NET API
Например, создадим такую программу на C#:
using System;
namespace ConsoleApplication1 { class Program { static int Run(string arg) { Console.WriteLine("Hello from .NET " + Environment.Version.ToString()); Console.ReadKey(); return 0; }
static void Main(string[] args) { Run(""); } } }
Скомпилируем ее, получаем файл Program.exe. Создадим проект С++, добавим в него файл Program.exe и создадим файл ресурсов resource.rc следующего содержания:
#define IDR_RCDATA1 101
IDR_RCDATA1 RCDATA "Program.exe"
Напишем на С++ код загрузчика, который находит первую установленную версию CLR, загружает ее, извлекает из ресурсов программу на C# во временную папку и запускает ее:
#include #include #include #include
#pragma comment(lib, "mscoree.lib")
#define IDR_RCDATA1 101
int wmain(int argc, wchar_t* argv[]) { LPCWSTR prog_name = L"Program.exe"; //имя программы на C#
//построим путь к временному файлу WCHAR temppath[300] = L"c:\\temp\\"; GetTempPath(300,temppath); wcscat(temppath,prog_name);
//извлечем программу из ресурсов HRSRC myResource = ::FindResource(NULL, MAKEINTRESOURCE(IDR_RCDATA1), RT_RCDATA); UINT Size = ::SizeofResource(NULL, myResource); HGLOBAL myResourceData = ::LoadResource(NULL, myResource); void* pMyBinaryData = ::LockResource(myResourceData); FILE* f = _wfopen(temppath,L"wb"); fwrite(pMyBinaryData,Size,1,f); fclose(f);
//инициализация CLR... HRESULT hr; ICLRMetaHost *pMetaHost = NULL; ICLRRuntimeInfo *pRuntimeInfo = NULL; ICLRRuntimeHost *pClrRuntimeHost = NULL; IEnumUnknown* pEnum= NULL; ICLRRuntimeInfo* pInfo= NULL; IUnknown* pUnk = NULL;
hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&pMetaHost)); if(FAILED(hr)){printf("CLRCreateInstance failed
");goto End;}
//поиск установленных версий CLR... pMetaHost->EnumerateInstalledRuntimes(&pEnum); if(FAILED(hr)){printf("EnumerateInstalledRuntimes failed
");goto End;}
ULONG c= 0; WCHAR buffer[250]; DWORD cch = 250;
while(1){ if(pInfo!=NULL){pInfo->Release();pInfo = NULL;} if(pUnk!=NULL){pUnk->Release();pUnk = NULL;} if(pRuntimeInfo!=NULL){pRuntimeInfo->Release();pRuntimeInfo = NULL;}
hr = pEnum->Next(1,&pUnk,&c); if(hr != S_OK)break;
pUnk->QueryInterface(IID_ICLRRuntimeInfo, (void**)&pInfo); if(FAILED(hr)){printf("QueryInterface failed
");continue;}
pInfo->GetVersionString(buffer,&cch); if(FAILED(hr)){printf("GetVersionString failed
");continue;}
hr = pMetaHost->GetRuntime(buffer, IID_PPV_ARGS(&pRuntimeInfo)); if(hr == S_OK){break;} else {wprintf(L".NET %s: GetRuntime HRESULT 0x%x
",buffer,(UINT)hr);} }
if(pRuntimeInfo == NULL){printf("Failed to initialize CLR
");goto End;}
/* Можно также указать версию явно, например: pMetaHost->GetRuntime(L"v2.0.50727", IID_PPV_ARGS(&pRuntimeInfo)); pMetaHost->GetRuntime(L"v4.0.30319", IID_PPV_ARGS(&pRuntimeInfo)); и т.п. */
hr = pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_PPV_ARGS(&pClrRuntimeHost)); if(FAILED(hr)){printf("GetInterface failed
");goto End;}
//запуск CLR hr = pClrRuntimeHost->Start(); if(FAILED(hr)){printf("Start failed
");goto End;}
//Запуск программы на C# DWORD pReturnValue; hr = pClrRuntimeHost->ExecuteInDefaultAppDomain( temppath, L"ConsoleApplication1.Program", //класс L"Run", //метод L"", //параметр &pReturnValue); if(FAILED(hr)){printf("ExecuteInDefaultAppDomain failed 0x%x
",(UINT)hr);goto End;}
End:
//Освобождение ресурсов if(pMetaHost != NULL) pMetaHost->Release(); if(pRuntimeInfo != NULL) pRuntimeInfo->Release(); if(pClrRuntimeHost != NULL) pClrRuntimeHost->Release(); if(pEnum != NULL) pEnum->Release(); if(pInfo != NULL) pInfo->Release(); if(pUnk != NULL) pUnk->Release(); return 0; }
В результате программа, собранная под .NET 2.0, при его отсутствии будет запускаться на имеющейся версии .NET, как и при использовании параметра supportedRuntime
Источники:
Embedding supportedRuntime into exe file - ответ Ondrej Svejdar
How to load a custom binary resource in a VC++ static library as part of a dll? - ответ LihO

Как перегрузить оператор для класса с произвольным типом

как я могу перегрузить оператор "+", чтобы можно было получить сумму двух узлов двоичного дерева поиска, учитывая то, что тип я у них сделал произвольным, но если будет тип Int у узлов, то тогда можно сложить, а если другой тип, то нельзя.
Вот код:
class Node { internal T value;
public static Node operator +(Node A, Node B) { return new Node(A.value + B.value); }
public int Balance { get { if (Left == null && Right == null) return 0; else if (Left == null && Right != null) return 0 - Right.Height; else if (Left != null && Right == null) return Left.Height; return (Left.Height - Right.Height); } private set { } } public int Height { get { if (Left == null && Right != null) return 1 + Right.Height; else if (Left != null && Right == null) return 1 + Left.Height; else if (Left != null && Right != null) { if (Left.Height >= Right.Height) return Left.Height + 1; else return Right.Height + 1; } else return 0; }
private set { }
}
Я хочу
сделать так, чтобы эти оператором можно было воспользоваться только если тип значения узла Int не использовать для этого отдельный новый класс IntNode : Node , а сделать это прямо в Node
Мне выводит такую ошибку:
Тип одного из параметров бинарного оператора должен быть вмещающим.


Ответ

сделать так, чтобы эти оператором можно было воспользоваться только если тип значения узла Int
Невозможно. Это невозможно даже в C++ с его текстовыми шаблонами формата "найти-заменить" (оператор будет доступен, но при компиляции вывалится 10КБ текста ошибок в потрохах инклюдов).
Если класс имеет разные члены в зависимости от параметров, то это не один класс. Вряд ли от этого принципа отступятся.
не использовать для этого отдельный новый класс IntNode : Node, а сделать это прямо в Node
Много вариантов:
Построить Expression с оператором, скомпилировать. Сгенерировать IL в рантайме. Воспользоваться отражениями. Воспользоваться dynamic, который воспользуется отражениями.
Чистого варианта нет. Возможно, когда-нибудь будет, но я бы не сильно надеялся, что это случится скоро: у задачи Exploration: Shapes and Extensions нет ни статуса, ни майлстона (даже "X.0").

Ошибка при переводе выражения в обратную польскую запись

Имеется код:
#include #include using namespace std; struct stack { char info; stack* next; }; void addToStack(char sym, stack *&begin); void showStack(stack *begin); int priority(char op); void showElementsInBrackets(string &output, stack *&begin); void executeFromStackElements(string &output, stack *&begin); int main() { stack *begin = NULL; string input, output = ""; cin >> input; for (int i = 0; i < input.length(); i++) { if (input[i] >= 'a' && input[i] <= 'z') { output += input[i]; } else if (input[i] == '+' || input[i] == '-' || input[i] == '*' || input[i] == '/' || input[i] == '%' || input[i] =='(') { if (begin == NULL || input[i] == '(') { addToStack(input[i], begin); } else { if (priority(begin->info) <= priority(input[i])) { addToStack(input[i], begin); } else { executeFromStackElements(output, begin); addToStack(input[i], begin); } } } else if (input[i] == ')') { showElementsInBrackets(output, begin); } } executeFromStackElements(output, begin); cout << "Output:" << endl; cout << output << endl; system("pause"); return 0; }
void addToStack(char sym, stack *& begin) { stack *t = new stack; t->info = sym; t->next = begin; begin = t; }
void showStack(stack * begin) { stack *t = begin; while (t != NULL) { cout << t->info << endl; t = t->next; } }
int priority(char op) { if (op == '(') { return 1; } else if (op == '+' || op == '-') { return 2; } else if (op == '*' || op == '/' || op == '%') { return 3; } }

void showElementsInBrackets(string & output, stack *& begin) { while (begin->info != '(' && begin != NULL) { output += begin->info; begin = begin->next; } begin = begin->next; }
void executeFromStackElements(string & output, stack *& begin) { while (begin != NULL) { output += begin->info; begin = begin->next; } }
Задача - перевод выражения в ОПЗ. Однако при определенном вводе, возникают проблемы со скобками. Например, при вводе a+bcd+(e-f)(gh+i), возникает ошибка
Вызвано исключение по адресу 0x010F3CD3 в OPZ.exe: 0xC0000005: нарушение прав доступа при чтении по адресу 0x00000000. И указывает на строку
while (begin->info != '(') {
Смотрю по отладке, там выходная строка это abcd**+ef-gh*(*+i+ Как я понимаю, ошибка из-за того, что открывающая скобка извлекается из стека, но не понимаю, почему это происходит


Ответ

первая ошибка:
stack *begin = NULL;
поскольку после прочтения буквы в следующем цикле begin остается нулевым, а компилятор не сможет осуществить проверку:
else { if (priority(begin->info) <= priority(input[i])) //...
поэтому:
stack *begin = new stack;
и не связанные с вашим вопросом ошибки:`
вторая ошибка:
вы нигде не удаляете обьекты, созданные в свободной области памяти через new, т.е. обьекты стека.
третья ошибка:
вы не возвращаете из функции int priority(char op) ничего, если op не является ни один из вами перечисленных символов (лучше возвращать ноль и это использовать в ваших условиях, т.е. если priority(char op)== 0, значит` op не является символом математической операции
и напоследок: еслибы вы хранили один string("*/()%+-"}, то использовав string::find могли бы сделать этот же код компактней и с меньшим количеством if/else ов

Преобразование случайной величины с равномерным распределением в величину с нормальным распределением

У меня есть некое кол-во случайных величин float в диапазоне [0;1] и эти величины имеют равномерное распределение.
Если такая величина X имеет нормальное распределение, то, величина K = m + a * tan(PI*(X-0.5)) имеет распределение коши.
Возможно ли по аналогии преобразовать такую величину X, в величину имеющую нормальное распределение?


Ответ

Написал грубо и точно ;) функцию InverseErf. Она очень сложна для вычислений.
// g++ inverf.cpp -o inverf # include # include // -1 => -Inf ; 0 => 0 ; +1 => Inf // -0.85 .. +0.85 => кубически // 0.85 .. 0.99 => сложно double InverseErf(double x){ bool flagneg = (x < 0.0); x=fabs(x); double result; if(x<0.85) result =(0.886+(-0.315+0.773*x)*x)*x; else { x=log(1.0-x); double const HalfPi = 1.57 ; result = sqrt(-x-log(-HalfPi*(log(HalfPi)+2.0*x))/2.0);} return flagneg ? -result : result ; }
double SimpleToNormal(double x , double med , double sigma){ return med + sqrt(2.0)*sigma*InverseErf(2.0*x-1.0);}
int main() { std::cout<<"inverf(0.999)="<Метод Мюллера спровоцировал на ещё один красивый вариант формулы InverseErf
double InverseErf2(double x){ double result = sqrt(-log(1.0-x*x))*0.9; return (x < 0.0) ? -result : result ; }

Содержит ли normal elements - custom elements?

Входит ли custom elements в группу normal elements?
Из одной главы я понял что существуют несколько типов групп элементов, самая большая это normal elements. Но я так и не понял входит ли туда custom elements
В пункте сказано:
Normal elements: All other allowed HTML elements are normal elements
В этой ссылке говорится что любые определения в пространстве содержатся в http://www.w3.org/1999/xhtml
А также цитата:
The term "HTML elements" refers to any element in that namespace, even in XML documents.
Но вот определения custom elements нет в http://www.w3.org/1999/xhtml , значит ли это что custom elements не входит в группу normal elements?


Ответ

Все исходит из того, что XHTML является подмножеством языка XML. В языке XML вы можете создавать и использовать абсолютно любые теги, которые только ваша душа пожелает. Это Custom Elements:
<Планеты> <Планета ID="1"> <Название>Меркурий <Планета ID="2"> <Название>Сатурн
А в XHTML прописаны только известные браузерам теги для которые он может генерировать внешний вид, эти элементы называются Normal Elements:
Заголовок Содержимое документа
То есть по факту Custom Elements это огромная группа элементов в которую так же (теоретически) входят и Normal Elements. Но шанс встретить Custom Elements в разметке мизерный.
Правда стандарт HTML накладывает ограничения на имена Custom Elements: RuSO: Нестандартные HTML теги

GNU Readline, статическое подключение к Qt

Имеется Qt Creator с собранным Qt с флагом -static. Библиотеки qt успешно вшиваются в программу, а вот readline (GNU Readline) никак не желает. Каким образом надо настроить .pro - файл, чтобы readline вшилась в программу?
ОС: Ubuntu 14.xx. Файл libreadline.a в системе есть.
P.S.: проект с открытым исходным кодом будет, так что про GNU в курсе.


Ответ

Сразу предупреждаю, на ответ не тянет, но в комментарий не поместится.
Собрал тест с readline (но без QT -)).
В самом деле
gcc -o t-r t-readline.c -static -lreadline
выдает предупреждения для некоторых функций libc (связанных с аутентификацией) и ошибки на отсутствие функций tgetent, tputs, tgetflag и т.п., вызываемых из функций библиотеки readline
Понятно, что я не задал линкеру какую-то библиотеку (или несколько).
Узнать, какие библиотеки нужны помогает утилита ldd (print shared object dependencies).
Итак, собираем shared версию
gcc -o t-r t-readline.c -lreadline
и запускаем ldd
avp@avp-ubu1:hashcode$ ldd -v ./t-r linux-vdso.so.1 => (0x00007ffeb73e5000) libreadline.so.6 => /lib/x86_64-linux-gnu/libreadline.so.6 (0x00007fb39dd17000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb39d94d000) libtinfo.so.5 => /lib/x86_64-linux-gnu/libtinfo.so.5 (0x00007fb39d724000) /lib64/ld-linux-x86-64.so.2 (0x00007fb39df5d000)
Version information: ./t-r: libc.so.6 (GLIBC_2.7) => /lib/x86_64-linux-gnu/libc.so.6 libc.so.6 (GLIBC_2.4) => /lib/x86_64-linux-gnu/libc.so.6 libc.so.6 (GLIBC_2.2.5) => /lib/x86_64-linux-gnu/libc.so.6 /lib/x86_64-linux-gnu/libreadline.so.6: libtinfo.so.5 (NCURSES_TINFO_5.0.19991023) => /lib/x86_64-linux-gnu/libtinfo.so.5 libc.so.6 (GLIBC_2.11) => /lib/x86_64-linux-gnu/libc.so.6 libc.so.6 (GLIBC_2.14) => /lib/x86_64-linux-gnu/libc.so.6 libc.so.6 (GLIBC_2.15) => /lib/x86_64-linux-gnu/libc.so.6 libc.so.6 (GLIBC_2.4) => /lib/x86_64-linux-gnu/libc.so.6 libc.so.6 (GLIBC_2.3.4) => /lib/x86_64-linux-gnu/libc.so.6 libc.so.6 (GLIBC_2.2.5) => /lib/x86_64-linux-gnu/libc.so.6 libc.so.6 (GLIBC_2.3) => /lib/x86_64-linux-gnu/libc.so.6 /lib/x86_64-linux-gnu/libc.so.6: ld-linux-x86-64.so.2 (GLIBC_2.3) => /lib64/ld-linux-x86-64.so.2 ld-linux-x86-64.so.2 (GLIBC_PRIVATE) => /lib64/ld-linux-x86-64.so.2 /lib/x86_64-linux-gnu/libtinfo.so.5: libc.so.6 (GLIBC_2.3) => /lib/x86_64-linux-gnu/libc.so.6 libc.so.6 (GLIBC_2.14) => /lib/x86_64-linux-gnu/libc.so.6 libc.so.6 (GLIBC_2.16) => /lib/x86_64-linux-gnu/libc.so.6 libc.so.6 (GLIBC_2.4) => /lib/x86_64-linux-gnu/libc.so.6 libc.so.6 (GLIBC_2.3.4) => /lib/x86_64-linux-gnu/libc.so.6 libc.so.6 (GLIBC_2.2.5) => /lib/x86_64-linux-gnu/libc.so.6
Из полученного вывода делаем предположение, что скорее всего нам нужна libtinfo
Пробуем
avp@avp-ubu1:hashcode$ gcc -o t-r t-readline.c -static -lreadline -ltinfo /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libreadline.a(complete.o): In function `rl_username_completion_function': (.text+0x3f69): warning: Using 'getpwent' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libreadline.a(tilde.o): In function `tilde_expand_word': (.text+0x1c4): warning: Using 'getpwnam' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libreadline.a(shell.o): In function `sh_get_home_dir': (.text+0xf9): warning: Using 'getpwuid' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libreadline.a(complete.o): In function `rl_username_completion_function': (.text+0x3f5f): warning: Using 'setpwent' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/libreadline.a(complete.o): In function `rl_username_completion_function': (.text+0x4009): warning: Using 'endpwent' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking avp@avp-ubu1:hashcode$
смотрим результат
avp@avp-ubu1:hashcode$ file t-r t-r: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=e0ee17d4201c7070bf650e9ac2bac441f6628a51, not stripped avp@avp-ubu1:hashcode$
потом слегка "тестируем"
avp@avp-ubu1:hashcode$ ./t-r > djjdjj line: djjdjj > kdkk dkkdkk dk line: kdkk dkkdkk dk > kdkk dkkm 49949 dkk dk line: kdkk dkkm 49949 dkk dk > End avp@avp-ubu1:hashcode$
и видим, что затея удалась.
P.S. Warnings, наверное, тоже можно побороть.

Kак активировать Aякс при нажатие Enter в поле input

Надо отправлять Aяксом инфу из поля на сервер (при этом, при нажатии на Enter, должна отправляться эта инфа) без использования


Ответ

Примерно так
var element = document.querySelector("input"); element.addEventListener('keydown', function(e){ var key = e.keyCode ? e.keyCode : e.which; if (key == 13) { var request = new XMLHttpRequest(); var formData = new FormData(); formData.append("input", this.value) request.open("POST", "url"); request.send(formData); } });

Выполнять действие пока нажата кнопка

Нужна кнопка нажав, на которую можно выполнить действие и если кнопка зажата дальше чем, скажем, 200 мс., то выполнять действие до тех пор, пока кнопка не будет отпущена. Но оказывается не все так просто. Я не могу просто написать в вызове что-то вроде:
if(pressed){ Thread.sleep(100); doIt(); }
Это остановит поток пользовательского интерфейса. Значит это надо перенести в другой поток.
То есть, по нажатию кнопку должен создаваться новый поток, который будет следить за тем нажата ли кнопка, сколько прошло времени,выполнять нужное действие.
К тому же, обязательно придется проследить чтобы поток был завершен вместе с закрытием приложения и т.д.
Может есть другие разумные способы решить данную задачу? Идеально если бы был какой-то функционал отложенной задачи, по типу __Platform.runLater__ , но только выполнить задачу через 100 мс, но я ничего подобного не нашел.


Ответ

Написал вот такую вот конструкцию.
private Thread pressingThread;
@FXML void onPress() { System.out.println("do something"); final int initDelay = 200; final int repeatDelay = 50; pressingThread = new Thread(() -> { try { Thread.sleep(initDelay); while (true) { Platform.runLater(() -> System.out.println("do something again")); Thread.sleep(repeatDelay); } } catch (InterruptedException ignored) { } }); pressingThread.setDaemon(true); pressingThread.start(); }
@FXML void onRelease() { pressingThread.interrupt(); }
Создается поток, который ждет необходимое время, потом в бесконечном цикле передает управление в поток пользовательского интерфейса нужное действие. Чтобы завершить работу необходимо вызывать метод interrupt().
Пробовал реализовать через переменную pressed, которая хранила бы состояние кнопки, и потом проверять не зажата ли кнопка, но тут есть тонкость, что если быстро нажать дважды на кнопку, то можно создать два потока, которые будут думать что кнопка не была отпущена. Потому все равно придется использовать interrupt()
Ред. Переписал в более удобный вид
import javafx.application.Platform;
public class DoWhilePressed { private int initDelay = 200; private int repeatDelay = 50; private Runnable doWhilePressed = ()->{};
private Thread pressingThread;
private pressed = false; public void press(){ if(pressed)return; pressed = true; doWhilePressed.run(); pressingThread = new Thread(() -> { try { Thread.sleep(initDelay); while (true) { Platform.runLater(() -> doWhilePressed.run()); Thread.sleep(repeatDelay); } } catch (InterruptedException ignored) { } }); pressingThread.setDaemon(true); pressingThread.start(); }
public void release(){ pressed = false; pressingThread.interrupt(); }
public int getInitDelay() { return initDelay; }
public DoWhilePressed setInitDelay(int initDelay) { this.initDelay = initDelay; return this; }
public int getRepeatDelay() { return repeatDelay; }
public DoWhilePressed setRepeatDelay(int repeatDelay) { this.repeatDelay = repeatDelay; return this; }
public Runnable getDoWhilePressed() { return doWhilePressed; }
public DoWhilePressed setDoWhilePressed(Runnable doWhilePressed) { this.doWhilePressed = doWhilePressed; return this; } }
Использовать можно как
private DoWhilePressed doWhilePressed = new DoWhilePressed() .setInitDelay(300) .setRepeatDelay(30) .setDoWhilePressed(() -> System.out.println("pressed"));
@FXML void onPress() { doWhilePressed.press(); }
@FXML void onRelease() { doWhilePressed.release(); }

Qt под android 7+

Всем доброго времени суток. Занимаюсь разработкой qt под android и начал сталкиваться с проблемой отсутствия интернета на андроид 7 и выше в приложении, при том что интернет в телефоне есть. Вот вопрос, который уже поднимал здесь, но его решение рассчитано на android studio, а не на qt: internet android 7+ Как можно запросить права на интернет в рантайме(qt 5.10.1)? пытаюсь это сделать такой конструкцией, но результата нет:
#include "my_app.h" #include #ifdef ANDROID #include #endif #include
bool checkPermission(const QString& perm) { #ifdef ANDROID QtAndroid::PermissionResult r = QtAndroid::checkPermission(perm); if(r == QtAndroid::PermissionResult::Denied) { QtAndroid::requestPermissionsSync( QStringList() << perm ); r = QtAndroid::checkPermission(perm); if(r == QtAndroid::PermissionResult::Denied) { QMessageBox::information(0, "Ошибка", "получить разрешение не удалось"); return false; } } #endif return true; }
int main(int argc, char *argv[]) {
checkPermission("android.permission.ACCESS_WIFI_STATE"); checkPermission("android.permission.ACCESS_NETWORK_STATE"); checkPermission("android.permission.INTERNET");
QApplication a(argc, argv); MyApp w; w.show();
return a.exec(); }


Ответ

Всё оказалось банально. В android 7+ нет поддержки ssl "из коробки" (google убрал). Обычный http заработал без проблем

Где реализован IEnumerator?

У меня появился вопрос, который не дает мне покоя вот уже несколько часов. Для того, чтобы использовать foreach для кастомной коллекции, нужно реализовать метод интерфейса IEnumerable.
IEnumerator IEnumerable.GetEnumerator(){ return arr.GetEnumerator(); }
С этим все ясно. Но какой класс реализует интерфейс IEnumerator? По началу я думал System.Array, но после того, как я не увидел IEnumerator в списке родителей System.Array решил обратиться сюда.


Ответ

IEnumerator реализован типом, объект которого возвращает arr.GetEnumerator()
IEnumerator IEnumerable.GetEnumerator() { IEnumerator result = arr.GetEnumerator(); Console.WriteLine(result.GetType().FullName); return result; }
Тип возвращаемого объекта - System.Array.SZArrayEnumerator. Вот этот SZArrayEnumerator и реализует IEnumerator

Политика конфиденциальности (Privacy policy) для android приложения

Пришло письмо от Google
Hi developers at Starikov Mark, After review, (название приложения), (пакет приложения), has been removed from Google Play due to a policy violation. This app won’t be available to users until you submit a compliant update. Issue: Violation of Usage of Android Advertising ID policy and section 4.8 of the Developer Distribution Agreement Google Play requires developers to provide a valid privacy policy when the app requests or handles sensitive user or device information. We’ve identified that your app collects and transmits the Android advertising identifier, which is subject to a privacy policy requirement. If your app collects the Android advertising ID, you must provide a valid privacy policy in both the designated field in the Play Console, and from within the app. Next steps: Submit your app for another review Read through the Usage of Android Advertising ID and User Data policies, as well as the Developer Distribution Agreement, and make appropriate changes to your app. If you decide to collect sensitive user information, be sure to abide by the above policies, and include a link to a valid privacy policy on your app's store listing page and within your app. Make sure that your app is compliant with all other Developer Program Policies. Additional enforcement could occur if there are further policy violations. Sign in to your Play Console and submit the update to your app. Alternatively, you may opt-out of this requirement by removing any requests for sensitive permissions or user data. If approved, your app will again be available with all installs, ratings, and reviews intact. If you’ve reviewed the policy and feel this removal may have been in error, please reach out to our policy support team. One of my colleagues will get back to you within 2 business days. Thanks for helping us provide a clear and transparent experience for Google Play users. Regards, Jaime The Google Play Team
Они проверили мое приложение, опубликованное в Google Play, и обнаружили то, что я использую ID рекламных баннеров, но не предоставляю Privacy Policy

Проблема заключается в следующем:
Я никогда не писал политику конфиденциальности и без понятия, что в ней писать, как оформлять и прочее. Необходимо выложить URL. У меня нет своего сайта или блога. Можно ли использовать README файл на GitHub или можно сделать это как-то проще? А также необходимо добавить в приложение. Куда именно ее нужно добавить? При первом запуске приложения? Где-нибудь в настройках или в разделе "О приложении"?
Очень буду благодарен за вашу помощь!


Ответ

Если никогда не писали политику конфиденциальности, то можете воспользоваться таким бесплатным инструментом, как Privacy Policy Generator.
Данный генератор учитывает такие сервисы, как Google Play Services, AdMob, Fabric, Crashlytics, Firebase Analytics и прочие. А также полностью бесплатный с открытым исходным кодом
Вы можете залить политику на GitHub или создать бесплатный Google сайт
Главное, чтобы было возможным указать URL на политику.
После всего, указать URL с политикой в Google Console и добавить (или создать) в раздел "О приложении". Если у Вас есть регистрация в приложении, то нужно, чтобы сначала была возможность ознакомиться с политикой, т.е. указать ссылку под кнопкой регистрация.

Как работать с git через HTTP прокси на Ubuntu?

При попытке извлечения кода git выдает ошибку: repo init -u git://...
Getting repo ... from git://... fatal: Unable to look up ... (port 9418) (Name or service not known)


Ответ

Нужно прописать параметры прокси в настройках git.
Создать скрипт git_proxy_command.sh
(echo "CONNECT $1:$2 HTTP/1.0"; echo; cat ) | nc прокси порт | (read a; read a; cat ) Установить переменную окружения GIT_PROXY_COMMAND
export GIT_PROXY_COMMAND=git_proxy_command.sh

Точка входа в .NET dll

Существует ли стандартный механизм, с помощью которого можно было бы автоматически выполнять определённый код при загрузке сборки в домен? Понятно, что реализовать такое несложно (пометить сборки своим атрибутом, указывающим тип, в статический конструктор которого следует поместить код инициализации, подписаться на AppDomain.CurrentDomain.AssemblyLoaded и дёргать в обработчике указанный тип, если сборка помечена), но всё же хотелось бы использовать стандартный механизм, если есть.


Ответ

Лично мне кажется, что event AssemblyLoaded как раз и является "стандартным механизмом" для таких целей.
А как его применять - т.е все то, что написано у вас в вопросе, включая использование кастомных атрибутов и пометку сборок - это просто некоторый syntactic sugar, который так или иначе диспатчит AssemblyLoaded

Другое дело, что в общем случае задача выполнения нужного кода в момент загрузки некоторой сборки нетривиальна и корректно решается только с помощью module initializers.
Рекомендую к прочтению .Net: Running code when assembly is loaded, если есть еще вопросы, то готов ответить.

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

В общем, нужна возможность помещать данные в буфер, как будто пользователь сам нажал Copy (Ctrl+V). Для IE есть простое решение: document.execCommand("Copy"); Для FF есть документация здесь (работоспособность не проверял). А как это сделать в Хроме и Сафари? Или может быть есть кроссбраузерное решение?


Ответ

Может быть Вам подойдет первая ссылка из гугла по запросу "jquery copy to clipboard"?

Модульное тестирование: работа с файлами

Как лучше всего тестировать работу с файлами? Например, я пишу тесты для класса работы с конфигами (чтение/запись). У него есть конструктор, в которое передается имя файла и методы get (получить значение параметра из конфиг. файла), set (установить значение параметра для конфиг. файла) и commit(применить изменения). Как сделать тестирование get и set - ясно. Но как (и надо ли) сделать работу с файлами при создании объекта и при сохранении? PS. Также, хотелось бы увидеть наиболее интересные, с Вашей точки зрения, книги по модульному тестированию (желательно, именно с такой теоретической информацией, без привязки к языку; ну или применительно к java/php). Книжку нашел вот такую. Вроде бы довольно интересная. Спасибо.


Ответ

Сам недавно столкнулся с подобной проблемой. Правда в связке .net+sqlite+nunit если интересно будет вот ссылка на статью Test a DataReader

Странная компиляция

Добрый день, есть у меня кусок кода, который я компилирую компилятором из VS 2008: while(static int i = 0 < 5) { i++; } Я ожидал от него исполнения тела цикла 5 раз. А вот что сделал компилятор: while(static int i = 0 < 5) 00401605 cmp dword ptr [i (40701Ch)],0 0040160C je wmain+2Fh (40161Fh) { i++; 0040160E mov ecx,dword ptr [i (40701Ch)] 00401614 add ecx,1 00401617 mov dword ptr [i (40701Ch)],ecx } Я ожидал от переменной i, что она, будучи статической, будет проинициализирована на стадии компиляции значением 0. Она действительно была проинициализирована на стадии компиляции, но значением 1 (!?). Мне абсолютно не понятно, почему условие цикла while, i<5, скомпилировалось как cmp dword ptr [i (40701Ch)],0 Исходя из листинга и пункта 1 очевидно, что программа уходит в бесконечный цикл. Я не понимаю какого-то соответствующего момента в C++, или это баг компилятора?


Ответ

Дело в приоритете операций. Сравнение имеет бОльший приоритет, чем присвоение. Поэтому сначала происходит сравнение констант 0 и 5, которое компилятор производит на этапе компиляции, а далее его результат (т.е. 1) присваивается переменной i.

Сериализация в Windows Phone 7.

Доброго времени суток, Хэшкод. Пытаюсь сделать Serializable class, по привычке пишу: using System.Runtime.Serialization;
namespace someNamespace { [Serializable()] public sealed class SomeClass: ISerializable { private readonly long someField; . . . } Однако под WinPhone7 это не работает, VS радостно заявляет, что не знает, что такое Serializable & ISerializable. Как это исправить? Приложение является портом с Java(Android), насколько помню Javовское "implements Serializable" это как раз C#-ское ":ISerializable". Не может такого быть, чтоб под winPhone не было такой возможности.


Ответ

Дело в том, что для Windows Phone нужно использовать вместо атрибута Serializable атрибут DataContract. Кое-какие подробности: DataContract DataContractSerializer

Как правильно логировать работу приложения?

Иногда хочется знать, что происходит с приложением в релизном варианте в боевом режиме под руками безжалостного пользователя... Возникают ошибки в приложении, а польз ователь ничего не может сказать, что он нажимал, куда мышкой водил, и какой текст набирал - как всегда оно само сломалось. Возникает вопрос, как правильно построить логику программы, чтобы было удобно логировать ее работу, а также удобно внедрять в готовые продукты. Сам экспериментирую на небольших программных продуктах (до 3000 строчек функционального кода на C#, но на мой взгляд пока не нашел идеального варианта). Из того что пробовал: Создание класса, со свойствами (для управления уровнем логирования, предварительных настроек). Класс инициализируется при старте программы, после из основного модуля ему передаются настройки, вызывается из основного модуля функция записи в лог. Сам класс решает писать ему только в свой список, в контрол, который ему передали, в файл. Нужно ли вообще писать это сообщение в зависимости от уровня логирования. ну и прочие фишечки рюшечки. недостаток того, что в каждой функции, которую хочется залогировать, приходится явно вызывать этот класс, требуется точно быть уверенным что он создан (ну это обходится созданием функции записи в лог, с проверкой созданного класса логирования и отловлей эксепшенов от него). Недостаточно глубоко в классы можно залезть. Создание класса приемерно такого же, за тем исключением, что запись вызывается путем отловли пользовательского сообщения на уровне приложения. Проблемы примерно такие же. Приходится каждое действие отдельно описывать в момент выполнения действий, что не удобно и загромождает полезный код программы. НУ и в случае падения программы, в лог данные могут не попасть, т.к. приложение не примет сообщение. Тоже что и выше, только ловля сообщений происходит в отдельном потоке - пробелемы схода - более менее серьезное падение программы приводит к повисанию потока, который соответственно сообщение не примет и не запишет в лог. Вариант с отдельным процессом для меня видится не лучшим вариантом. т.к. это лишние проблемы и не нужные вещи, к которым я крайне плохо отношусь. ИТОГО: Интересуют два момента: как писать в лог, не загромождая полезный код программы и не усложняя его чтение. как зафиксировать наиболее подробный лог, даже в случае падения, повисания программы.


Ответ

По общему вопросу. Log4Net - почти стандарт (не нужно изобретать велосипед) Может помочь AOP (типа PostSharp), в таком случае не нужно "коверкать" исходный код. как писать в лог, не загромождая полезный код программы и не усложняя его чтение. Писать в отдельный лог-файл или другое хранилище, очевидно же. Ну или в том же log4Net используются различные уровни записей. как зафиксировать наиболее подробный лог, даже в случае падения, повисания программы. Наиболее подробный лог получается, как ни странно, при логировании исключения. Во-первых что-бы иметь актуальный стек, ошибка не должна скрываться во "внутренних деталях реализации" и дойти до глобального обработчика ошибок в своем начальном виде или со своими дополнениями. Во-вторых, должна обработаться либо с записью в какое-то хранилище, либо передана по почте разработчикам и прочее.