Собственно,есть проэкт в VS 2008 C++,у фрейма есть кнопка и picturebox.По нажатии на кнопку должна отрисоваться сетка из прямоугольников.(100х100 где то) Дело в том что после нажания кнопки происходит отрисовка,но по завершению результат пропадает,приходится нажимать 2 раз,и тогда от нормально и длительно отображается,хотя иногда тоже пропадает.Мне непонятно почему такое может происходить??Еще мне немного не нравится та скорость,с которой происходит отрисовка,можно ли ее как нибудь ускорить?Дело в том,что потом для каждой "клетки" будет задаваться свой собственный цвет.
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e)
{
const int N=100;
double size=1.0;
double x,y;
double h=size/N;
double Xkoef= (pictureBox1->Width)/size;
double Ykoef= (pictureBox1->Height)/size;
Graphics^ g = pictureBox1->CreateGraphics();
Pen^ bluePen = gcnew Pen( Color::Blue,1.0f );
SolidBrush^ hBrush = gcnew SolidBrush (Color::Red);
for ( int i=1 ; i<=N ; i++)
{
for ( int j=0 ; j<=N ; j++)
{
x= (i)*h * Xkoef;
y= (j)*h * Ykoef;
g->FillRectangle( hBrush,Rectangle(x, y,(x + h*Xkoef),(y + h*Ykoef)));
g->DrawRectangle(bluePen,Rectangle(x, y,(x + h*Xkoef),(y + h*Ykoef)));
}
}
}
А сколько пикселей занимает 1 прямоугольник? Если примерно до 20х20, то понятно, почему тормоза.
Используй StretchBlt.
Ну или напрямую пиши в видеобуфер.
Krjuger, тип RectangleF как-то больше подходит для заталкивания в него вещественных значений, чем Rectangle. Опять же, не надо перерасчитывать значения X в цикле по J, результаты будут одинаковыми, вынеси вычисления из внутреннего цикла. Но это так, для проформы. На скорость отрисовки влияния не окажет.
С точки зрения алгоритма - все прекрасно, почему сбоит реализация в VS 2008 - непонятно. Проверил на C# - рисует прямоугольнички как положено, ничего не исчезает.
Кстати, обход по икс должен быть внутри обхода по игреку. Это тоже может ускорить.
Ну просто тут такое дело,что эта задача напрямую связана с той,что была до этого,тобиш расчитать поле температур,но преподавателю оказалось мало полученных результатов,ему еще все в картинках подавай.Суть в том что у меня есть некая фигура заданная в виде массива и в каждой ячейке храниться "температура" в данной точке.Мне надо все отградуировать считая, что минимальная температура, это красный цвет, а максимальная это синий.Граници прямоугольников я потом вообще уберу,потому что преподаватель нам давал код на делфи ,который совершал необходимые действия с словами " портируйте сами".И там было x := ((i-1)*h + h/2) * Xkoef; вместо x= (i)*h * Xkoef;,и выводило явно не то что надо(было небольшое наложение прямоугольников).Поэтому,чтобы исправить, я взял и отрисовывал сетку,чтобы убедиться и исправить,хотя принципи такое наложение возможно поможет для больших прямоугольников,дескать получение промежуточного цвета,хотя я не проверял как себя будет вести это наложение.
> Распахнутое на весь экран окно (при расширении 1920*1080) заполняется разными цветами меньше чем за 2 секунды.
У тебя тоже селерон-600?
Или может таки применить нормальный StretchBlt?
> А StretchBlt тебе что, очень поможет (даже если его импортировать), если не все цвета одинаковые?
Да. Я так понял, ОП хочет вывести маленькую картинку в виде большой. Делает это с помощью кучи прямоугольников. StretchBlt делает то же самое.
> Ну, будет работать моментально на красных ячейках. Как начнешь рисовать реальную картинку с градациями цветов - получишь еще бОльшие тормоза.
StrechBlt тормознее, чем куча прямоугольников?!
То у тебя красно-чёрное дерево быстрее, чем сортировка подсчётом, теперь это.
> Это ты о чем, вообще?
А, это не ты был? Типа я поверил, гы.
> Еще раз: если б знать, что ТС будет использовать только 16 цветов
Какая разница, сколько.
> ради того, чтоб программа выполнялась на секунду быстрее
Вывод картинки в течение двух секунд - это дохрена.
> Откуда копировать-то прямоугольнички? А?
Как откуда. Из другого DC, само собой.
А уж попиксельно вывести массив в DC, созданный через CreateDIBSection - это вообще простой цикл, выполняется очень быстро. Только делать это надо не через SetPixel, а через то самое "нельзя, но если очень хочется, то можно", которое ты так стремишься сделать "нельзя". Понимаешь, все запретные концепции хоть и мешают жить большую часть времени, но когда они становятся смертельно нужны, то приходится опускаться и до них. А терпеть 2-секундный вывод чисто ради принципов - это уже фанатизм.
Или ты подумал, что я для каждого прямоугольника отдельно StretchBlt вызываю? Я что, похож на идиота? Нет, я сначала рисую картинку из "прямоугольничков размером 1х1" (при помощи неприятных и грязных, но простых действий), а потом её растягиваю.
> А если очень хочется, и делаешь "можно" - то потом это падает.
Что же у вас тестирование не работает?
А ничего, что в основе любого кода, если глубже ковырнуть, лежить то самое "нельзя". И первый компилятор писался на "нельзя", потому что другого не было.
Так то паранойя не имеет смысла, можно много до чего дойти.
> Быстро - когда неуправляемый код вызывается из неуправляемого же. А вызов unmanaged кода из managed - потеря производительности. В разы... Не забыл? Затраты на вызов могут перекрыть прирост производительности, ага. Было смертельно нужно? Ну, и получил тормоза при смешивании кодов... Чья концепция оказалась в выигрыше?
Неужели в точканете всё так плохо? Наверняка там есть готовый класс для копирования массива в память БМП, который там хоть через unsafe{} работает, главное, что он есть и отлажен. Просто надо побольше использовать стандартных алгоритмов для всяких вещей типа растягивания картинки итд, иначе либо руками вычислять все адреса всех пикселей (для игр иногда балуюсь этим), либо тормозить с прямоугольниками.
В конце концов, специально для тех, кому страшно, можно для сравнения нарисовать маленькую картинку (с прямоугольниками 1х1) через тупой SetPixel, и растянуть её
Я благодарен за такой интерес к этой теме,но после 4 или 5 поста я перестал понимать вообще что либо.
public:
void FillRectangle(Brush^ brush,
float x, float y, float width, float height)
void Button1Click(object sender, EventArgs e)работает на порядок быстрее...
{
const int N=100;
float size=1.0f;
float h=size/N;
float Xkoef= (pictureBox1.Width)/size;
float Ykoef= (pictureBox1.Height)/size;
Graphics g = pictureBox1.CreateGraphics();
Pen bluePen = /*gc*/new Pen( Color.Blue, 1.0f );
Pen redPen = /*gc*/new Pen( Color.Red, 1.0f );
SolidBrush hBrush = /*gc*/new SolidBrush (Color.Red);
SolidBrush hBrush2 = /*gc*/new SolidBrush (Color.Blue);
float y = 0;
for(int j = 0; j <= N; j++)
{
float x = h * Xkoef;
for(int i = 1; i <= N; i++)
{
if ((i + j) % 2 == 1)
{
g.FillRectangle( hBrush, x, y, h * Xkoef, h * Ykoef);
}
else
{
g.FillRectangle( hBrush2, x, y, h * Xkoef, h * Ykoef);
}
x += h * Xkoef;
}
y += h * Ykoef;
}
}
Да я сам чето тормознул,повелся на то,что преподаватель давал......
SolidBrush^ hBrush = gcnew SolidBrush (Color::FromArgb(255,0,0));
hBrush = gcnew SolidBrush (Color::FromArgb(2*i,0,j));
Зачем же выделять память, если можно сделать изменение свойства:
SolidBrush^ hBrush = gcnew SolidBrush (Color::FromArgb(255,0,0));?
// а потом, в цикле:
hBrush->Color = Color::FromArgb(2*i, 0, j);
Спасибо за совет,сам бы врятли додумался
Новую тему создавать не стал,так как немного мелочным посчитал проблему.
У меня есть файл в котором лежит число(размерность матрицы),затем исходная матрица и преобразованная матрица(размерность одинаковая).Можно ли как то считать быстро ненужную мне исходную матрицу ,чтобы быстро приступить к нужной,или можно сразу как нибуть переместиться на нужную позицию,но как тогда вычислить где именно необходимая мне позиция.
Так же меня немного смутил такой момент,когда я записывал в файл,то делалось это достаточно просто.
freopen("info.txt","w",stdout);
cout<< m*N << '\n';
FILE* pFile;
pFile=fopen("info.txt","r");
for(int i = 0; i <= N; i++)
{
for(int j = 0; j <= N; j++)
{
fscanf(pFile,"%lf",&U[i][j]);
}
}
freopen("info.txt","r", stdin);Но я бы все-таки сделал это через StreamReader:
// ...
cin >> value;
void btnReadMatrixClick(object sender, EventArgs e)(VS у меня нету, так что код - на C#). Тестировал на небольших матрицах (элементы в строке разделены пробелами, но в принципе, Split принимает любой разделитель...) - все прекрасно работает.
{
openFileDialog1.ShowDialog();
TextReader sr = new System.IO.StreamReader(openFileDialog1.FileName);
int Len = Convert.ToInt32(sr.ReadLine());
string s = sr.ReadToEnd();
string[] sArr = s.Split('\n');
int[,] iArr = new int [Len, Len];
// Вот, собственно, пропускаем первую часть, от 0 до Len - 1...
for(int i = Len; i < sArr.Length; i++)
{
int j = 0;
foreach(string st in sArr[i].Split(' '))
{
iArr[i - Len, j++] = Convert.ToInt32(st);
}
}
}
Ну а тут возникли некоторые проблемы.
Дело в том,что Split,как утверждает MSDN работает в С++ немного не так как в C#.
int Len = Convert::ToInt32(myStream->ReadLine());
String^ s = myStream->ReadToEnd();
array<String^>^ sArr = s->Split('\n');
int[,] iArr = new int [Len, Len];
// Вот, собственно, пропускаем первую часть, от 0 до Len - 1...
for(int i = Len; i < sArr->Length; i++)
{
int j = 0;
for each(String^ st in sArr[i]->Split(' '))
{
iArr[i - Len, j++] = Convert::ToInt32(st);
}
}
Возвращаясь к тем же баранам.Тот код ,что ты скидывал прекрасно работает для целых чисел.Я заменил строку.
iArr[i - Len, j++] = Convert::ToInt32(st); на iArr[i - Len, j++] = Convert::ToDouble(st); и тут возникли проблемы,когда число целое все прекрасно скидывается и записывается,но когда число дробное,то выдает сразу ошибку.
String^ GetExceptionType( Exception^ ex )
{
String^ exceptionType = ex->GetType()->ToString();
return exceptionType->Substring( exceptionType->LastIndexOf( '.' ) + 1 );
}
void ConvertToDouble( String^ numericStr, Object^ defaultValue )
{
try
{
defaultValue = Convert::ToDouble( numericStr );
}
catch ( Exception^ ex )
{
defaultValue = GetExceptionType( ex );
}
ConvertToDouble( st, temp );
U[i - Len][j++] =temp;
> ,что число дабл храниться в в памяти с точкой
ЧЁ
Просто во американским стандартам, отражённым во всех ЯП, вещественные числа пишутся через точку. Но дядя Билл решил, что раз в России принята запятая, то пусть и стандартный разделитель в русской версии винды будет запятая, что влияет на НЕКОТОРЫЕ функции ввода (и преобразования строк в числа).
Короче, я не знаю, как в С++.НЕТ это делается, но у тебя либо есть способ поменять разделитель для функции преобразования, либо взять другую функцию для преобразования строки в число.
Да решение оказалось действительно достаточно простым.
NumberFormatInfo^ Provider = gcnew NumberFormatInfo;
Рrovider->NumberDecimalSeparator = ".";
// и вызов
U[i - Len][j++] = Convert::ToDouble(st, Provider);
В общем я наконецто доделал.Протестировал на разных N правда до 45,вроде работает.
Если надо, могу выложить код.
Для моих граничных условий и функции при N=45 получается такой результат:
http://iscr.ru/1304853733/