Мой новый любимый псевдоним, основанный на bonyiii 's answer (upvoted), и мой собственный ответ о " Передайте аргумент команде alit Git ":
git config alias.restore '!f() { git checkout $(git rev-list -n 1 HEAD -- $1)~1 -- $(git diff --name-status $(git rev-list -n 1 HEAD -- $1)~1 | grep '^D' | cut -f 2); }; f'
Я потерял файл, удаленный по ошибке несколькими коммитами назад? Quick:
git restore my_deleted_file
Кризис предотвращен.
Роберт Дайли предлагает в комментариях следующий псевдоним:
restore-file = !git checkout $(git rev-list -n 1 HEAD -- "$1")^ -- "$1"
И jegan добавляет в комментарии :
. Для установки псевдонима из командной строки I использовала эту команду:
git config --global alias.restore "\!git checkout \$(git rev-list -n 1 HEAD -- \"\$1\")^ -- \"\$1\""
Да, это слишком медленно.
Я столкнулся с этой проблемой несколько лет назад во время разработки Paint.NET (с самого начала, и это было довольно сложно!). Производительность рендеринга была ужасной, так как она всегда была пропорциональна размеру растрового изображения, а не размеру области, которую было сказано перерисовать. То есть частота кадров уменьшалась по мере увеличения размера растрового изображения, а частота кадров никогда не увеличивалась, поскольку размер недопустимой области / области перерисовки уменьшался при реализации OnPaint () и вызове Graphics.DrawImage (). Небольшое растровое изображение, скажем, 800x600, всегда работало нормально, но большие изображения (например, 2400x1800) были очень медленными. (В любом случае, вы можете предположить, что в предыдущем абзаце ничего лишнего не происходило, например, масштабирование с помощью какого-нибудь дорогого бикубического фильтра, что могло бы негативно повлиять на производительность.)
Можно заставить WinForms использовать GDI вместо GDI + и избегайте даже создания объекта Graphics
за кулисами, после чего вы можете наложить поверх него еще один инструментарий рендеринга (например, Direct2D). Однако это не просто. Я делаю это в Paint.NET, и вы можете увидеть, что требуется, используя что-то вроде Reflector в классе с именем GdiPaintControl
в DLL-библиотеке SystemLayer, но для того, что вы делаете, я бы посчитал это последним средством.
Однако используемый вами размер растрового изображения (800x1200) все равно должен работать достаточно хорошо в GDI +, не прибегая к расширенному взаимодействию, если только вы не нацеливаетесь на что-то столь же низкое, как Pentium II с 300 МГц. Вот несколько советов, которые могут помочь:
Graphics.DrawImage()
, и особенно если это 32-разрядное растровое изображение с альфа-канал (но вы знаете , что он непрозрачный, или вам все равно), затем установите Graphics.CompositingMode
в CompositingMode.SourceCopy
перед вызовом DrawImage()
(обязательно установите его обратно в исходное значение после, в противном случае обычные рисунки примитивов будут выглядеть очень некрасиво). Это пропускает много дополнительных математических вычислений на пиксель. Graphics.InterpolationMode
не настроен на что-то вроде InterpolationMode.HighQualityBicubic
. Использование NearestNeighbor
будет самым быстрым, хотя, если есть какое-либо растяжение, оно может выглядеть не очень хорошо (если только оно не растягивается ровно в 2, 3, 4 раза и т. Д.) Bilinear
обычно является хорошим компромиссом. Вы никогда не должны использовать ничего, кроме NearestNeighbor
, если размер растрового изображения соответствует области, в которую вы рисуете, в пикселях. Graphics
, данный вам в OnPaint()
. OnPaint
. Если вам нужно перерисовать область, позвоните по номеру Invalidate()
. Если вам нужно, чтобы розыгрыш произошел прямо сейчас, позвоните Update()
после Invalidate()
. Это разумный подход, поскольку сообщения WM_PAINT (что приводит к вызову OnPaint()
) являются сообщениями с «низким приоритетом». Любая другая обработка, выполняемая оконным менеджером, будет выполняться в первую очередь, и, в противном случае, вы можете получить много пропущенных и пропущенных кадров. System.Windows.Forms.Timer
в качестве частоты кадров / таймера не очень хорошо работает. Они реализованы с использованием Win32 SetTimer
и приводят к сообщениям WM_TIMER, которые затем приводят к возникновению события Timer.Tick
, а WM_TIMER - другое сообщение с низким приоритетом, которое отправляется только тогда, когда очередь сообщений пуста. Вам лучше использовать System.Threading.Timer
, а затем использовать Control.Invoke()
(чтобы убедиться, что вы на правильном пути!) И вызывать Control.Update()
. Control.CreateGraphics()
. (следствие «всегда рисовать в OnPaint()
» и «всегда использовать Graphics
, данное вам OnPaint()
») OnPaint()
в классе, который вы пишете, который должен быть получен из Control
. Производные от другого класса, например PictureBox
или UserControl
, либо не добавят никакой ценности для вас, либо добавят дополнительные издержки. (КСТАТИ PictureBox
часто неправильно понимают. Вы, вероятно, почти никогда не захотите его использовать.) Надежда, которая помогает.
GDI +, вероятно, не лучший выбор для игр. DirectX / XNA или OpenGL должны быть предпочтительными, так как они используют любое графическое ускорение и очень быстро.
GDI + никоим образом не является демоном скорости. Любые серьезные манипуляции с изображениями обычно должны идти в нативную сторону (вызовы pInvoke и / или манипуляции с помощью указателя, полученного путем вызова LockBits
.)
Вы изучали XNA / DirectX / OpenGL? Это фреймворки, разработанные для разработки игр, и они будут на порядок более эффективными и гибкими, чем при использовании фреймворков UI, таких как WinForms или WPF. Все библиотеки предлагают привязки C #.
Вы можете вводить в нативный код, используя такие функции, как BitBlt , но есть и дополнительные затраты, связанные с пересечением границы управляемого кода.
Хотя это древний вопрос, а WinForms - это древний фреймворк, я хотел бы поделиться тем, что я только что обнаружил случайно: рисование растрового изображения в BufferedGraphics и его последующее отображение в графическом контексте, предоставляемом OnPaint, представляет собой способ быстрее рисования растрового изображения непосредственно в графическом контексте OnPaint - по крайней мере, на моем компьютере с Windows 10.
Это удивительно, потому что интуитивно я предполагал, что копирование данных будет несколько медленнее (и поэтому я подумал, что это обычно оправдано только тогда, когда кто-то хочет делать двойную буферизацию вручную). Но очевидно, что с объектом BufferedGraphics происходит нечто более сложное.
Поэтому создайте BufferedGraphics в конструкторе элемента управления, который будет содержать растровое изображение (в моем случае я хотел нарисовать полноэкранное растровое изображение 1920x1080):
using (Graphics graphics = CreateGraphics())
{
graphicsBuffer = BufferedGraphicsManager.Current.Allocate(graphics, new Rectangle(0,0,Screen.PrimaryScreen.Bounds.Width,Screen.PrimaryScreen.Bounds.Height));
}
и использовать его в OnPaint (при аннулировании OnPaintBackground )
protected override void OnPaintBackground(PaintEventArgs e) {/* just rely on the bitmap to fill the screen */}
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = graphicsBuffer.Graphics;
g.DrawImage(someBitmap,0,0,bitmap.Width, bitmap.Height);
graphicsBuffer.Render(e.Graphics);
}
вместо наивного определения
protected override void OnPaintBackground(PaintEventArgs e) {/* just rely on the bitmap to fill the screen */}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.DrawImage(someBitmap,0,0,bitmap.Width, bitmap.Height);
}
См. На следующих скриншотах сравнение частоты результирующего события MouseMove (я реализую очень простой элемент управления рисованием растровых изображений). Вверху находится версия, где растровое изображение рисуется напрямую, в нижней части используется BufferedGraphics. В обоих случаях я двигал мышь примерно с одинаковой скоростью.