Flutter for Windows Desktop: Getting Started
Learn how to set up a development environment and create a simple Flutter calculator app for Windows Desktop. By Karol Wrótniak.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Flutter for Windows Desktop: Getting Started
20 mins
- Getting Started
- Installing Visual Studio
- Enabling Desktop Support in Flutter
- Creating the Project
- Developing the Button
- Developing the Grid of Buttons
- Building the Business Logic
- Developing the Calculation Engine
- Binding UI with Business Logic
- Developing Features for Desktop
- Supporting Mouse Input
- Supporting Keyboard Input
- Handling Keystrokes
- Handling Key Events
- Managing Window Size
- Preventing Window Maximization
- Integrating with System Clipboard
- Polishing the Project
- Where to Go From Here
Developers often use Flutter to develop mobile apps. Starting from version 2.10, it supports Windows as a target platform. Let’s check how to develop the production-level Windows apps with Flutter.
In this tutorial, you’ll learn how to set up a development environment and create a simple calculator app. We’ll focus on key concepts and basic business logic operations. In the process, you’ll learn:
- Setting up environment.
- Creating a Flutter desktop project.
- Handling keyboard input.
- Managing window size.
This tutorial covers the Windows platform only. But, almost everything should work on macOS and Linux. You only have to adjust the keyboard shortcuts.
Getting Started
To compile the Flutter desktop application for Windows, use a PC with Windows OS. A virtual machine like VMware or VirtualBox with a Windows guest also will work. Unfortunately, Flutter isn’t currently supporting cross-compilation.
To build Flutter apps on Windows you’ll need:
- Flutter SDK
- IDE which supports Flutter eg. Android Studio
- Visual Studio 2022
Installing Visual Studio
This tutorial doesn’t cover Flutter SDK and IDE setup processes. Instead, we assume you can already build Flutter mobile apps. If not, check the Windows install documentation of Flutter SDK and Android Studio.
When installing Visual Studio, select Desktop development with C++ workload. It should contain the MSVC v143 for your PC ABI (x64/x86 in case of Intel and compatible CPUs):
Enabling Desktop Support in Flutter
Before you open or create a desktop project, enable the Windows support in Flutter. This is a global setting. You have to do it only once. Execute the following command in the terminal:
flutter config --enable-windows-desktop
Open and run the starter project from the attachment to this tutorial. You can press Shift+F10 in Android Studio. This will check whether your setup is correct. If all is OK, you should see the standard Flutter Demo app:
If you see CMake compilation errors, it usually means inconsistent Visual Studio installation. Specific versions of Flutter only supports specific versions of Visual Studio and MSVC. In the case of Flutter 2.10, it’s Visual Studio 2022 and MSVC v143.
Creating the Project
You’ll create the FCalc app, which is a simple calculator. It supports only integers (no fractions), two arithmetic operations: + and -, and clearing (AC).
You can enter data by clicking buttons, using a keyboard or pasting them from the system clipboard. The final layout looks like this:
Developing the Button
Start from the widget for a button. It’s an elementary building block of the calculator. First, add the following code in a separate file tile.dart
.
import 'package:flutter/material.dart';
class Tile extends StatelessWidget {
final String symbol;
final Function(String) onTap;
const Tile(
this.symbol,
this.onTap, {
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) => Material(
child: InkWell(
//1
onTap: () => onTap(symbol),
//2
child: Center(
child: Text(
symbol,
style: const TextStyle(
fontSize: 26,
color: Color(0xFF333333), //grey
),
),
),
),
color: const Color(0xFFFCB526), //yellow
);
}
It contains the following elements:
- A tap handler, mouse clicks and presses of widgets that currently have a focus (moved using Tab).
- Centered label using Ray Wenderlich brand colors.
The Material and InkWell widgets are here to provide a visual feedback on taps.
Developing the Grid of Buttons
Create a CalculatorBody
widget with grid of Tile
widgets and a placeholder for a display. It’s a skeleton of the calculator. Note the order of digits: 7, 8, 9, 6, 5 and so on. After that, place the following code inside a calculator_body.dart
file, and press Alt+Enter to add missing imports:
class CalculatorBody extends StatelessWidget {
CalculatorBody({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) => Column(
//1
textDirection: TextDirection.ltr,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
//TODO display
GridView.count(
//2
shrinkWrap: true,
//3
padding: const EdgeInsets.all(20),
//4
crossAxisSpacing: 10,
mainAxisSpacing: 10,
//5
crossAxisCount: 3,
children: [
Tile('7', (symbol) {
//TODO action
}),
//TODO rest of the tiles
],
),
],
);
}
Here’s what the code above does:
- Aligns the display on the right side. Even if the locale uses right-to-left direction, e.g., Arabic or Hebrew.
- Shrink the content to prevent infinite expansion.
- Set the gaps between the grid and window borders.
- Set the distance between adjacent buttons.
- Set number of columns.
Building the Business Logic
The business logic should have some unit tests and formal descriptions, e.g., using a state machine diagram. This article focuses on getting started on desktop app development, not on the arithmetic or the clean code. So it will only describe the algorithm shortly.
Start from creating the class for a calculator with ValueNotifier for an output. All the business logic will go there. Put the code in calculator.dart
file.
class Calculator {
final displayNotifier = ValueNotifier('0');
}
Note that CalculatorBody
was a stateless widget. Only the value notifier holds the state.
You need two arithmetic operations. Add a simple enum for them in the same calculator.dart
file:
enum Operator { plus, minus }
Developing the Calculation Engine
Now you’re ready to add the core logic, specifically the ability to append digits and operators to the current state. Add the following code to the Calculator
class:
Operator? _pendingOperation;
int? _operand;
bool _wasDigitJustAppended = false;
void appendOperator(Operator operation) {
if (_wasDigitJustAppended) {
//1
switch (_pendingOperation) {
case Operator.plus:
_updateDisplay(_operand! + int.parse(displayNotifier.value));
break;
case Operator.minus:
_updateDisplay(_operand! - int.parse(displayNotifier.value));
break;
//2
case null:
_operand = int.parse(displayNotifier.value);
break;
}
}
_wasDigitJustAppended = false;
//3
_pendingOperation = operation;
}
void _updateDisplay(int result) {
_operand = result;
displayNotifier.value = result.toString();
}
void appendDigit(String digit) {
//4
if (!_wasDigitJustAppended) {
displayNotifier.value = '';
}
//5
_wasDigitJustAppended = true;
displayNotifier.value += digit;
}
At the beginning, a display shows 0
. There are no pending operations and no operands (numbers) on the stack. That’s because a user has not pressed any key yet. The result depends on what kind of input has arrived (a digit or an operation) and what kind of action was previously taken. If no previous actions were taken, we take the initial state into account.
The algorithm works as follows (the order of the lines of code doesn’t match the order of a typical use scenario):
- If an operation is pending, compute the result out of the first operand. Then, the current display content.
- If a user has pressed the plus or minus (and only digits before), remember the number entered so far.
- Remember the last operation as a new pending one.
- If a previous key (before a digit) was the plus or minus sign, clear the display. It contains the result of some operation, not the digits of the current number.
- If a user has pressed the digit, append it to a display.
Note the text (String) is a storage of a content of a display. We convert texts to numbers (int type) only before the arithmetic operations. It’s easier to build the multidigit numbers as texts if the user can append single digits.