среда, 19 октября 2011 г.

Qthread подсчет максимальной величины символов (задача Nival)

Полгода назад компания Nival прислало мне желание меня лицезреть и тест который нужно сделать.На что я плюнул на эту затею, не потому что я что то плохое имею к Nival
а просто знаю что в gamedev платят через чур мало :)
Но тест вот лежал, и решил его сделать на Qt

Смысл задания сводиться к тому, что бы загрузить любой документ и найти максимальную
последовательность , то есть 0,1,2,33,55,66,33 тут максимум 6 и так далее по всему файлу.
Ну и последняя фича, нужно все это сделать в потоке.
reliase:

#ifndef CALCULATE_H
#define CALCULATE_H

#include <QThread>
#include <QByteArray>
#include <QFile>
#include <QMutex>

namespace test
{
 class Calculate : public QThread
 {
  Q_OBJECT
 public:
  Calculate(QString _filename , int _iCountThread) : QThread(0) ,m_iCountThread(_iCountThread) {

   QFile file(_filename);
   if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
   {
    qDebug("error not found file");
   }else // file found
   {
    m_currentlyElements = file.readAll();
    qDebug("%d size block %d  filename %s ",m_iCountThread,m_currentlyElements.size(),_filename.toStdString().c_str());

   }
   m_tmpElements.clear();
  }
 protected:
  void run()
  {
   int iCount = 0;
   while(reCalculate(iCount++))
   {}
  }

  virtual ~Calculate() {}
 private:
  int m_iCountThread;
  QByteArray m_maxElements , m_currentlyElements , m_tmpElements;
  QMutex m_mutex;

  bool reCalculate(int m_iCount)
  {
   m_mutex.lock();
   // делаем перебор и заполняем темлайтный массив
    if (m_iCount + 1 < m_currentlyElements.size()) // max size + 1
    {
     if (m_currentlyElements.at(m_iCount) <= m_currentlyElements.at(m_iCount + 1) )
     {
      m_tmpElements += m_currentlyElements.at(m_iCount);
     }else
     {
      if (m_maxElements.size() < m_tmpElements.size())
      {
       m_maxElements = m_tmpElements;
      }
     m_tmpElements.clear();

     }
    }else
    {
     int count = 0;
     while(count != m_maxElements.size())
     {
      qDebug("valuse %d (%d)",m_maxElements.at(count),m_iCountThread);
      count++;
     }
     qDebug("destroy %d thread",m_iCountThread);
     m_mutex.unlock();
     return false;// finish search
    }

   if (m_maxElements.size() < m_tmpElements.size())
    m_maxElements = m_tmpElements;

   m_mutex.unlock();
   return true;// loop more
  }
 };
}
#endif // CALCULATE_H

test::Calculate *val = new test::Calculate("filename");
val->start();

сразу извиняюсь за форматирование он тут суров.

суббота, 17 сентября 2011 г.

создание своего QVariant

Что такое QVariant вы надеюсь знаете, и что там есть эээ штук 10 дефолтных типов
а что бы сделать свой .. я как раз и расскажу.В общем тут не сложно :)

1. что нужно это сделать класс какой нужно что бы QVariant знал.
class dataLobbyList
{
public:

	dataLobbyList(QString _host,QString _port,QString _login,QString _pass)
		: m_Host(_host),m_Port(_port) , m_Login(_login) , m_Password(_pass)
	{}
	dataLobbyList(){}
	virtual int	getTypeData(){return TYPE_LOBBY_LIST;}

	QString	m_Host;
	QString	m_Port;
	QString	m_Login;
	QString	m_Password;
};
Q_DECLARE_METATYPE(dataLobbyList)

И главное в нем , это последняя строчка, она делает регистрацию в метатипах.
Что бы как раз QVariant  знал ваш класс.
2. ну и использование данной вещи.

DialogConnectInfo dialog("host","test","123","123");

QVariant var;
var.setValue<DialogConnectInfo>(dialog);

// ...

DialogConnectInfo bar2 = var.value<DialogConnectInfo>();
var.typeName();  // Foo::Bar

ниже пример не мой )) но я думаю и так понятно.

QTableView и роли.

Когда я начал изучать этот класс (потому что там есть Model и фильтры для него)
я столкнулся с ролями,
на что они похожи ??? а похожи они на простые фабрики классов.
1. параметр это QVariant
2.это как раз и есть значение фабрики

enum ItemDataRole {
        DisplayRole = 0,
        DecorationRole = 1,
        EditRole = 2,
        ToolTipRole = 3,
        StatusTipRole = 4,
        WhatsThisRole = 5,
} more...

то есть что бы сделать какую нить роль для QTableView
нужно ...


QAbstractItemModel_model = m_view->model();
 _model->setData(_model->index(0, 1),QColor(0,0,222), Qt::BackgroundColorRole);
тока модель нужно получить

И получается что для 0 столбца 1 ячейка будет иметь цвет QColor(0,0,222)

И кстати что я заметил , если вы для всего проекта забьете QStyleSheet и сделаете роль.
То роль является круче чем стиль :) 

ps надеюсь я разьяснил что такое роль в Qt , и это применительно не только для модели
но и везде где есть роль :) а их там много

сетевая часть recv

даю реально рабочий кусок из проекта.
Blob это класс контейнер фабрики классов

uint32_t CClientTransport::recv(ClientNode* _pNode)
{

	Blob bb;
	uint8_t* pBuffer = new uint8_t[4];
	int32_t nReceived, nReceivedTotal = 0;
	while(true)
	{
		nReceived = m_pSocket->read((char*) pBuffer + nReceivedTotal, 4);
		nReceivedTotal += nReceived;
		if (nReceivedTotal >= 4)
			break;
		m_pSocket->waitForReadyRead(1000);
	}
	bb.assign(pBuffer, nReceivedTotal, 4);
	int32_t uPacketSize;
	bb >> uPacketSize;


	nReceivedTotal = 0;
	pBuffer = new uint8_t[4096];
	while(true)
	{
		nReceived = m_pSocket->read((char*) pBuffer + nReceivedTotal, 4096);
		nReceivedTotal += nReceived;
		if (nReceivedTotal >= uPacketSize)
			break;
		m_pSocket->waitForReadyRead(1000);
	}
	bb.assign(pBuffer, nReceivedTotal, 4096);
	//bb.print(16, 4);

	uint32_t uCrc32;

	// просто забираем размер пакета
	// забираем CRC32
	bb >> uCrc32;
	// и сравниваем с CRC32 полученных данных пакета
	if (bb.crc32() != uCrc32)
			throw Exception(EX_CT(Exception::CONNECTIONERROR, "CRC32 error"));

	uint32_t uMessageType = bb.readUInt32();
	vn::MessageWrap msgw = _pNode->messageFactory(uMessageType);
	msgw.message()->Serialize(bb, false);
	_pNode->receiveMessage(msgw);
	return uMessageType;
}
В общем в заборе пакета я пользуюсь асинхронным методом m_pSocket->waitForReadyRead(1000);
в общем она похожа если бы я под виндой делал Sleep(1000)
просто ожидание, тормозов в общем не наблюдалось, но мы этот параметр минимизировали до 100 мс

Сетевая часть.

Давно не залезал, вот решил рассказать о тех проблемах
которые я встретил на своем тернистом пути :)

1. если вы хотите сделать нормальное приложение без тормозов и "затыков"
не используйте методы
waitForConnected
waitForReadyRead
waitForBytesWritten
все это приводит к выше перечисленным.
для этого используйте сигналы.
void readyRead();


void connected()
void disconnected()


пример , получения данных с сокета.

m_pSocket = new QTcpSocket();
connect(m_pSocket,SIGNAL(connected()),this,SLOT(sl_conect()));

connect(m_pSocket,SIGNAL(creadyRead()),this,SLOT(sl_ReadyRead()));

И все будет норм.

пятница, 6 мая 2011 г.

создание маштабированного окна с элементами


#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsItem>
 
class CircleItem : public QGraphicsItem
{
public:
 CircleItem( qreal radius, QGraphicsItem* parent = 0 )
 : QGraphicsItem( parent )
 , radius_( radius ) {}
 virtual ~CircleItem() {}
 void paint( QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0 )
 {
  painter->drawEllipse( QRectF( -radius_ / 2, -radius_ / 2, radius_, radius_ ) );
 }
 QRectF boundingRect() const
 {
  return QRectF( -radius_ / 2, -radius_ / 2, radius_, radius_ );
 }
private:
 qreal radius_;
};
 
class GraphicsView : public QGraphicsView
{
public:
 GraphicsView( QWidget* p = 0 ) : QGraphicsView( p ) {}
 void resizeEvent( QResizeEvent* e )
 {
  fitInView( scene()->sceneRect() );
 }
};
 
int main( int argc, char** argv )
{
 QApplication app( argc, argv );
 
 GraphicsView gv;
 QGraphicsScene scene( -150, -150, 300, 300 );
 
 gv.setScene( &scene );
 gv.setRenderHint( QPainter::Antialiasing );
 
 for( qreal r = 20; r < 300; r += 10 )
  scene.addItem( new CircleItem( r ) );
 
 gv.show();
 
 return app.exec();
}
 

namespace AQP

встретил такой helpers

void hoursMinutesSecondsForMSec(const int msec, int *hours,int *minutes, int *seconds);
результат. вы даете ей msec микросекунды , а она вам возвращает
сколько это часов минут и секунда.
examples


QString MainWindow::minutesSecondsAsStringForMSec(qint64 msec)
{

    int minutes;
    int seconds;
    AQP::hoursMinutesSecondsForMSec(msec, 0, &minutes, &seconds);
    return QString("%1:%2").arg(minutes, 2, 10, QChar(' '))
                           .arg(seconds, 2, 10, QChar('0'));
}

Возвращает путь в котором лежит приложение qt

QString applicationPathOf(const QString &path)
{
    QDir dir(QApplication::applicationDirPath());
#ifdef Q_WS_WIN
    if (dir.dirName().toLower() == "debug" ||
        dir.dirName().toLower() == "release")
        dir.cdUp();
#elif defined(Q_WS_MAC)
    if (dir.dirName() == "MacOS") {
        dir.cdUp();
        dir.cdUp();
        dir.cdUp();
    }
#endif
    if (!path.isEmpty())
        dir.cd(path);
    return dir.canonicalPath();
}


буду по мере изучения добавлять 

УЧИМ QT НОВЫМ ТРЮКАМ

Нашел сайт где возможно изменить поведение и вид элементов контроля.

http://wiki.metrotek.spb.ru/wiki/%D0%A3%D1%87%D0%B8%D0%BC_Qt_%D0%BD%D0%BE%D0%B2%D1%8B%D0%BC_%D1%82%D1%80%D1%8E%D0%BA%D0%B0%D0%BC

четверг, 5 мая 2011 г.

Умные указатели

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


template<class T> class Holder{
mutable T *obj;
public:
Holder<T>()throw():obj(0) {}
Holder<T>(T *x) throw():obj(x){}
Holder<T>(const Holder<T> & q) throw(){obj=q.obj;q.obj=0;}
Holder<T> & operator=(const Holder<T> & q) throw(){
if (obj) 
dbgprintf(_T("Holder d'nt free object"));
obj=q.obj;q.obj=0;return *this;}
Holder<T> & operator=(T* q) throw(){
if (obj) 
dbgprintf(_T("Holder d'nt free object"));
obj=q;return *this;}
//AG212 ~Holder<T>(){if (obj) delete obj;}
  ~Holder<T>(){if (obj) delete obj; obj=NULL;}
inline void release() throw() {obj=0;}
inline operator T*() throw(){return obj;}
inline operator const T*() const throw(){return obj;}
inline T* value() throw(){return obj;}
inline const T* const_value() const throw(){return obj;}
inline T* operator->() throw(){return obj;}
inline const T* operator->() const throw(){return obj;}
inline void free(){if (obj) delete obj;obj=0;}
inline bool isEmpty() const throw(){return !obj;}
inline bool empty() const throw(){return !obj;}
inline bool operator!() const throw(){return !obj;}
inline operator bool()const throw(){return obj!=0;}
};

среда, 4 мая 2011 г.

vector удаление элементов




for (vector<N>::iterator it = vec.begin();it != vec.end(); )
{
 if (некое условие)
  it = vec.erase(it);
 else
  ++it;
}
Способом перебора мы обрабатываем условие , если оно равно true то 
удаляем элемент и получаем обратно следующий iterator
иначе просто переходим к другому элементу.

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

QT новый слой (окно)

Главная особенность , это то что я могу на 1 сцене сделать сколько угодно
независимых "слоев"
как выглядит этот "слой"

class KAsteroidsView : public QWidget
{
    Q_OBJECT
public:
    KAsteroidsView( QWidget *parent = 0);
    virtual ~KAsteroidsView();
private:
    QGraphicsScene field;
    QGraphicsView view;
}
KAsteroidsView::KAsteroidsView( QWidget *parent)
    : QWidget( parent),
      field(0, 0, 640, 440),
      view(&field, this)
{
    view.setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
    view.setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
    view.setCacheMode(QGraphicsView::CacheBackground);
    view.setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
    view.setOptimizationFlags(QGraphicsView::DontClipPainter
                              | QGraphicsView::DontSavePainterState
                              | QGraphicsView::DontAdjustForAntialiasing);
    view.viewport()->setFocusProxy( this );
}
В общем не чего запутанного тут нет.
1. инициализация размера "слоя"
2. передача QGraphicsView основные параметры отображения и указывания viewport

Структура QT приложения.QMainWindow

class TopLevel : public QMainWindow
{
    Q_OBJECT
public:
    TopLevel( QWidget *parent = 0);
    virtual ~TopLevel();
private:
// следующее окно или слой , кому как лучше 
    KAsteroidsView *view;
}
TopLevel::TopLevel( QWidget *parent)
    : QMainWindow(parent)
{
QWidget *border = new QWidget( this );
// настройка палитры по умолчанию 
    QPalette palette;
    palette.setColor(border->backgroundRole(), Qt::black);
    border->setPalette(palette);
// позиция в центр
    setCentralWidget( border );
    QVBoxLayout *borderLayout = new QVBoxLayout( border );
    borderLayout->addStretch( 1 );
// делаем Layout и тоже позицируем в центр 
    QWidget *mainWin = new QWidget( border );
    mainWin->setFixedSize(640, 480);
// делаем фиксированный размер 
    borderLayout->addWidget( mainWin, 0, Qt::AlignHCenter );
// добаляем в Layout основной слой отображения mainWin
    borderLayout->addStretch( 1 );

}
В этой части делаем инициализацию ТОП экрана (1 level) что бы добавить другое "окно"
с отдельными Сигналами и Слотами

...
        view = new KAsteroidsView( mainWin );
    view->setFocusPolicy( Qt::StrongFocus );
}