Консультация № 170834
27.07.2009, 13:31
0.00 руб.
0 25 3
Добрый день Уважаемые эксперты. Нужна помощь.
У меня была такая идея: написать программу чтобы при нажатии на кнопку одна из панелек двигалась на определеное расстояние. При нажатии на другую на другое и т д. Но столкнулся с тем что в
this->panel1->Location = System::Drawing::Point(21,32);
Нельзя вместо цифр указывать переменные. По подсказкам компилятора понял что можно использовать переменную int dw. Но это не выход из ситуации. Одной переменной мало...Ее сильно не посравниваешь в циклах ну и т д. Есть ли какое то решение этого вопроса?
И еще одно. Вторая проблемка. Как организовать так чтобы при нажатии на определенную кноппку на клавиатуре происходило определенное событие а не на кнопки и т д в форме... Заранее спасибо.

Обсуждение

Неизвестный
27.07.2009, 13:33
общий
Забыл указать. Компилятор МS VISUAL C++ 2008
Неизвестный
27.07.2009, 14:40
общий
это ответ
Здравствуйте, Dimon4ik.
Замечательно там переменные используются. Возможно, какая-то ошибка в коде. См. приложение. На форму надо добавить кнопку и установить ей этот обработчик.

У каждого экранного контрола (и у форм) есть события от клавиатуры. Они реагируют просто на нажания. Фильтровать нужные кнопки приходится уже в коде. Посмотрите события KeyDown, KeyUp, KeyPress и свойство контейнера KeyPreview.

Приложение:
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
int x=button1->Location.X;
int y=button1->Location.Y;
Point p(x+5, y+5);
button1->Location = p;
button1->Text=button1->Location.ToString();
}
5
Неизвестный
27.07.2009, 15:22
общий
По нажатию на кнопку мышкой выполняются действия
private: System::Void button2_MouseClick(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) {
int x=panel1->Location.X;
int y=panel1->Location.Y;
Point p(x+5, y);
this->panel1->Location = p;
}
А при нажатии на клавишу вниз не на NUM не на обычных стрелках ничего не происходит.
private: System::Void Form1_KeyUp(System::Object^ sender, System::Windows::Forms::KeyEventArgs^ e) {

int x=panel1->Location.X;
int y=panel1->Location.Y;
Point p(x+5, y);
this->panel1->Location = p;
}

А свойство контейнера как можно посмотреть. Этого тоже не понял..
Неизвестный
27.07.2009, 15:59
общий
У формы надо установить KeyPreview=true. Это там, где все свойства устанавливаете - Text, например.
Неизвестный
27.07.2009, 16:26
общий
Поставил там true.
Оставил всего два обьекта:
private: System::Void Form1_KeyUp(System::Object^ sender, System::Windows::Forms::KeyEventArgs^ e) {

int x=panel1->Location.X;
int y=panel1->Location.Y;
Point p(x+=5, y);
this->panel1->Location = p;
}
private: System::Void Form1_KeyDown(System::Object^ sender, System::Windows::Forms::KeyEventArgs^ e) {
int x=panel1->Location.X;
int y=panel1->Location.Y;
Point p(x, y+=5);
this->panel1->Location = p;}
};


При нажатии на любую из стрелок обьект движется только по иззменению Х. А при нажатии на любую букву по Y...
Чтото не пойму. Хотя указал же стрелки...
Неизвестный
27.07.2009, 17:22
общий
:)
KeyDown возникает после нажания на кнопку. Любую.
KeyUp - после того, как кнопка будет отпущена.
Это не для стрелок. Объект KeyEventArgs содержит поля, по которым можно определить нажатую/отпущенную кнопку и модификаторы (Shift, Alt, Ctrl). Обычно в этих обработчиках делают свитч по e.KeyCode или другому свойству (уже не помню точно). И в зависимости от основной кнопки и модификаторов запускают нужную функцию.

У вас в одном обработчике меняется X, в другом - Y. Вызываться вроде должны оба, тк кнопка нажимается и отпускается. += в данном случае лучше заменить на +. Смысла в изменении переменной нет.
Неизвестный
27.07.2009, 19:06
общий
это ответ
Здравствуйте, Dimon4ik.
Возможно Вам надо подобный обработчик.
Код:

System::Void Form1_KeyDown(System::Object^ sender, System::Windows::Forms::KeyEventArgs^ e)
{
static const Int32 movePoints=1;
if((e->Modifiers&(Keys::Alt|Keys::Control|Keys::Shift))==(Keys)0)
{
Point location=panel->Location;
switch(e->KeyCode)
{
case Keys::Up:
location.Y-=movePoints;
if(location.Y<0)
{
location.Y=0;
}
break;
case Keys::Down:
location.Y+=movePoints;
break;
case Keys::Left:
location.X-=movePoints;
if(location.X<0)
{
location.X=0;
}
break;
case Keys::Right:
location.X+=movePoints;
break;
default:
return;
}
panel->Location=location;
}
}

Прикрепил к ответу файл проекта.

Следует сказать, что это дурной тон в программировании интерфейса так делать. Вам следует взглянуть на тот подход, который используется в Qt и WPF, а именно на менеджеры компоновки.
5
Неизвестный
27.07.2009, 19:06
общий
это ответ
Здравствуйте, Dimon4ik.
Возможно Вам надо подобный обработчик.
Код:

System::Void Form1_KeyDown(System::Object^ sender, System::Windows::Forms::KeyEventArgs^ e)
{
static const Int32 movePoints=1;
if((e->Modifiers&(Keys::Alt|Keys::Control|Keys::Shift))==(Keys)0)
{
Point location=panel->Location;
switch(e->KeyCode)
{
case Keys::Up:
location.Y-=movePoints;
if(location.Y<0)
{
location.Y=0;
}
break;
case Keys::Down:
location.Y+=movePoints;
break;
case Keys::Left:
location.X-=movePoints;
if(location.X<0)
{
location.X=0;
}
break;
case Keys::Right:
location.X+=movePoints;
break;
default:
return;
}
panel->Location=location;
}
}

Прикрепил к ответу файл проекта.

Следует сказать, что это дурной тон в программировании интерфейса так делать. Вам следует взглянуть на тот подход, который используется в Qt и WPF, а именно на менеджеры компоновки.
Прикрепленные файлы:
5
Неизвестный
27.07.2009, 20:09
общий
Evgenijm, Спасибо. Понял.

Только вот одну вещь не могу понять. Выбрал цвет фона для панели Transparent. Нарисовал gif эскиз человечка и поставил его как background. Тоесть вышло что человечек на фоне картинки формы. Но при перемещении или компьютер не успевает или что то другое, некоторое время остается белый квадрат на том месте откуда перемещаюсь. И выходит не очень... Как это можно исправить?
Неизвестный
28.07.2009, 01:05
общий
Не совсем понял насколько проблемно это выглядит. Попробуйте установить свойство DoubleBuffered=true. Тогда содержимое формы будет рисоваться не на экране, а в картинке, и потом перерисовываться на экран. Это убирает мигания при перерисовке картинки.
Неизвестный
28.07.2009, 10:13
общий
Теперь белых полосок не возникает, но другая проблема. Тяжело обьяснить. Рисунок который движется находится в прямоугольной панели и эта панель когда перемещается или не успевает менять цвет за фоном или другое чтото. В общем при движении видно как движется не только рисунок а весь квадрат. Может, как говорит Micren, не стоит так делать? Только вот я не понял какой подход он предлагает...
Неизвестный
28.07.2009, 13:39
общий
Dimon4ik:
Вы можете поместить один рисунок там где Вам угодно, а не всю панель.
Неизвестный
28.07.2009, 19:20
общий
Как это сделать?
Неизвестный
28.07.2009, 20:37
общий
Dimon4ik:
А каким образом Вы поместили изображение?
Неизвестный
28.07.2009, 21:01
общий
Вот так :
http://s06.radikal.ru/i179/0907/a4/d339dbff02d6.jpg
Неизвестный
28.07.2009, 21:42
общий
Micren прав - не стоит. Вы это и сами видите :)
Подход зависит от количество и сложности "взаимоотношений" графических объектов.
Проблема:
Перемещение контролов - довольно затратное действие. Обычно перерисовывается сразу несколько разных контролов, находящихся друг над другом (окно - это тоже контрол). У них есть запрограммированные действия, вроде очистки региона (заливки цветом фона), рисовании на этом фоне рисунка и тд. Поскольку это все начинает выполняться в неконтролируемом нами порядке, возникают видимые дефекты.
Можете попробовать создать свой Control. И в его методе Paint рисовать картинку. Надо будет еще смотреть необходимые дополнительные действия. (По возникающим артефактам)
Но самый правильные способ - рисовать всю картинку игры без использования контролов. Надо в методе Paint перерисовывать все поле или его часть. У меня сейчас времени не очень много свободного, так что я не очень соображаю. Когда-то я занимался рисованием в контроле, но сейчас уже не помню. Еще в моих ответах есть один про простую игрушку. Попробуйте поискать.
Неизвестный
28.07.2009, 23:01
общий
При попытке запустить на C# ошибку выдает.
Error 1 'pk.Form1.Dispose(bool)': no suitable method found to override C:\Documents and Settings\User.COMP\Local Settings\Application Data\Temporary Projects\pk\Form1.Designer.cs 14 33 pk
Я еще поразбираюсь. Если смогу. Спасибо


Неизвестный
28.07.2009, 23:26
общий
Dimon4ik:
Вы бы лучше код или файл проекта прикрепили, а не фото.
Неизвестный
29.07.2009, 00:40
общий
Посмотрите ответ на этот вопрос. Отрисовка там начинается в методе PaintGame. Правда, она с использованием матричных преобразователей, но работала, вроде.
Неизвестный
29.07.2009, 02:24
общий
Dimon4ik:
Если уж Вам надо выводить графику подобную игровой, то для этого лучше использовать соответствующие средства. Windows Forms с устаревшим интерфейсом GDI не предназначена для таких задач. Довольно сложную анимацию можно использовать в WPF или же воспользоваться более специфическими инструментами наподобие XNA Game Studio, которую Вы можете скачать и установить бесплатно. ОТСЮДА. Вот пример части проекта на C# выполняющего задачу аналогичную Вашей.
Код:

Vector2 location = Vector2.Zero;
const float distance = 2.0f;

protected override void Update(GameTime gameTime)
{
GamePadState gamePadState=GamePad.GetState(PlayerIndex.One);
KeyboardState keyboardState=Keyboard.GetState();
if (gamePadState.Buttons.Back == ButtonState.Pressed ||
keyboardState.IsKeyDown(Keys.Escape))
{
this.Exit();
}

double gamePadMove = Math.Sqrt(Math.Pow(gamePadState.ThumbSticks.Left.X, 2) +
Math.Pow(gamePadState.ThumbSticks.Left.Y, 2));
if(gamePadMove<0.1)
{
if (keyboardState.IsKeyDown(Keys.Up))
{
location.Y -= distance;
}
if (keyboardState.IsKeyDown(Keys.Down))
{
location.Y += distance;
}
if (keyboardState.IsKeyDown(Keys.Left))
{
location.X -= distance;
}
if (keyboardState.IsKeyDown(Keys.Right))
{
location.X += distance;
}
}
else
{
location.X += gamePadState.ThumbSticks.Left.X * distance;
location.Y -= gamePadState.ThumbSticks.Left.Y * distance;
}
if (location.Y < 0)
{
location.Y = 0;
}
else
{
int bottom = Window.ClientBounds.Height - image.Height;
if(location.Y>bottom)
{
location.Y = bottom;
}
}
if (location.X < 0)
{
location.X = 0;
}
else
{
int right = Window.ClientBounds.Width - image.Width;
if(location.X>right)
{
location.X = right;
}
}
base.Update(gameTime);
}

protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);

spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Deferred, SaveStateMode.None);
spriteBatch.Draw(background, Vector2.Zero, Color.White);
spriteBatch.Draw(image, location, Color.White);
spriteBatch.End();

base.Draw(gameTime);
}

Причем поддерживается геймпад XBOX-360(написано и проверено мной лично ).
Установочный файл примера Вы можете скачать: http://rapidshare.com/files/261160091/XNA-Demo.rar
Неизвестный
29.07.2009, 19:30
общий
В WPF и XNA Game Studio используется c# ?
Неизвестный
29.07.2009, 19:33
общий
Dimon4ik:
Да
Неизвестный
29.07.2009, 19:43
общий
Спасибо большое!)
Теперь буду искать среди друзей того кто сможет скачать мне этот файл
Неизвестный
29.07.2009, 19:56
общий
Dimon4ik:
Цитата: 218629
Теперь буду искать среди друзей того кто сможет скачать мне этот файл

А чего так? С интернетом проблемы?
Неизвестный
08.08.2009, 23:01
общий
Да... Не безлимит...
Форма ответа