Pull to refresh

Веб приложение на Qt? Are you serious? Why not?

Время от времени на форумах рунета появляются люди, которые собираются писать веб приложение, restful api.
И тут подумал, а почему бы и нет?


Согласен, что иногда бывает неплохо иметь веб интерфейс к существующей программе. Пример таких программ Transmission, EiskaltDC++.

Существующие решения на Qt(которые нагуглил):

Не могу не упомянуть:


Почему не libqxt, QHttpServer? Потому что они асинхронные и не такие удобные как slim и mojolicious(видно сказывается сидение под Zenwalk).

Как выглядит Hello World:
	Gwido::Server server;
	server.setThreadPool(Gwido::Server::ThreadPoolPtr(new QThreadPool()));
	server.get("/hello_world.html",
			[](const Gwido::Request& request,
				      Gwido::Response& response)
			{
				response.header().set("Content-type", "text/html");
				auto& stream = response.stream();
				stream<<"<html><head><title>Gwido Hello Worl example</title></head><body>";
				stream<<"<h1>Hello World!</h1>";
				stream<<"</body></html>";
			});
	server.listen(QHostAddress::Any, 8080)


Hello World- это скучно, поэтому сделаем приложение рисующее множество Мандельброта, что бы хоть как-нибудь оправдать использования потоков.
Вид приложения
image


Установка обработчиков:
	server.get("/", titlePage);
	server.post("/", titlePage);
	server.get("/mandelbrod.png", mandelbrodImage);
	server.get("/icon32.png", [&](const Gwido::Request& request,
			Gwido::Response& response)
	{
		response.setType(Gwido::Response::Binary);
		response.header().set("Content-type", "image/png");
		response.setOutBinaryData(icon);
	});

Выдача страницы с формой:
	auto titlePage =
			[](const Gwido::Request& request,
					Gwido::Response& response)
			{
				response.header().set("Content-type", "text/html");
				auto& stream = response.stream();

				int width = extractInt(request.param("width"), 512);
				int height = extractInt(request.param("heght"), 512);
				double qmin = extractDouble(request.param("qmin"),-1.5);
				double qmax = extractDouble(request.param("qmax"), 1.5);
				double pmin = extractDouble(request.param("pmin"), -2.75);
				double pmax = extractDouble(request.param("pmax"), 0.75);

				stream<<"<html><head><title>Qt Web - Mandelbrot Example</title>";
				stream<<"<link rel='icon' type='image/png' href='/icon32.png' /></head><body>";
				stream<<"<h1>Qt Web - Mandelbrot Example</h1>";
				stream<<"<form action='/' method='post'>";
				stream<<" pMin: <input name='pmin' value='"<<pmin<<"'>";
				stream<<" pMax: <input name='pmax' value='"<<pmax<<"'><br>";
				stream<<" qMin: <input name='qmin' value='"<<qmin<<"'>";
				stream<<" qMax: <input name='qmax' value='"<<qmax<<"'><br>";
				stream<<" width(min 512): <input type='number' name='width' min=512 value='"<<width<<"'>";
				stream<<" height(min 512): <input type='number' name='heght' min=512 value='"<<height<<"'>";
				stream<< "<br><input type='submit' value='draw'>";
				stream<< "</form><image src='mandelbrod.png?"<<QString("width=%1&height=%2&qmin=%3&qmax=%4&pmin=%5&pmax=%6")
				.arg(width).arg(height)
				.arg(qmin).arg(qmax)
				.arg(pmin).arg(pmax)<<"'><br>";
				stream<<"</body></html>";
			};


Рисование картинки штука простая, и не стоит особого внимания:
код
	void mandelbrodImage(const Gwido::Request& request,
			Gwido::Response& response)
	{
		response.setType(Gwido::Response::Binary);
		response.header().set("Content-type", "image/png");

		int width = extractInt(request.param("width"), 512);

		int heght = extractInt(request.param("heght"), 512);
		QSize resultSize(width, heght);
		QImage image(resultSize, QImage::Format_RGB32);
		image.fill(Qt::black);

		double pMin = extractDouble(request.param("pmin"), -2.75);
		double pMax = extractDouble(request.param("pmax"), 0.75);
		double dp = (pMax - pMin) / (width);
		double qMin = extractDouble(request.param("qmin"), -1.5);

		double qMax = extractDouble(request.param("qmax"), 1.5);
		double dq = (qMax - qMin) / (heght);
		int M = 4;

		for (int h = 0; h < heght; ++h)
		{
			quint32 *scanLine = reinterpret_cast<quint32*>(image.scanLine(h));
			for (int w = 0; w < width; ++w)
			{
				std::complex<double> z0(0, 0);
				std::complex<double> c(pMin + w * dp, qMin + h * dq);
				double r = 0;
				int k = 0;

				std::complex<double> z;
				do
				{
					z = z0 * z0 + c;
					r = std::norm(z);
					++k;
					z0 = z;
				} while ((r <= M) && (k < COLOR_MAP_SIZE));
				if (r > M)
				{
					scanLine[w] = COLOR_MAP[k];
				}
				else if (k == COLOR_MAP_SIZE)
				{
					scanLine[w] = qRgb(0, 0, 0);
				}

			}
		}
		{
			QBuffer buff;
			buff.open(QIODevice::ReadWrite);
			image.save(&buff, "PNG");
			buff.seek(0);
			response.setOutBinaryData(buff.readAll());
		}
	}



Для REST не хватает реализации маршрутов в таком виде в каком они существуют в slim и mojolicious(Задачка непростая и требует много времени).

П. С.
Не отношусь к теме написанию веб приложений и rest api на Qt серьезно. Код.
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.